Skip to content
JavaScript console.log() Method: Complete Guide with Examples

16 Minutes

JavaScript console.log() Method: Complete Guide with Examples

Fix Bugs Faster! Log Collection Made Easy

Get started

console.log() is a foundational tool for developers learning JavaScript. It sends messages to the browser’s DevTools console, so we can see what our code is doing at runtime.

This allows us to:

  • Debug an emerging issue.
  • Inspect a variable.
  • Check how a function behaves.

Because it prints information directly to the console, we can observe values, program flow, and potential issues.

In this post we’re going to cover the basics of console.log() syntax, the nuances of formatting and the essential DevTools add-ons that turn console.log() from a window into a dashboard. Here’s a full breakdown of what you’ll learn.

What console.log() is used for

console.log() provides six specific functions that developers use regularly.

  • View data: See the current value of variables, expressions and function outputs.
  • Debug: Identify where bugs occur by checking what the code is doing at specific points.
  • Trace execution: Confirm whether a line of code is reached and in what order.
  • Check the structure of data: See shapes of objects, arrays and nested values.
  • Show diagnostic messages: Output information without affecting the visible UI.
  • Provide simple output: Act as JavaScript’s “print” function in browser environments.

As you can see, console.log() is a real Swiss army knife. It lets us keep tabs on practically all facets of our codebase and allows us to fix problems not just proactively but pre-emptively.

Now let’s switch into the practical stuff.

JavaScript console.log() syntax

The console.log() method outputs one or more values to the browser’s console. You can pass any type of data, and the console will display each argument in order.

Common syntax patterns include:

console.log(value);               // single value
console.log(a, b, c);             // multiple values
console.log(object);              // objects and arrays
console.log(label, value);        // labeled output

How this might look in real code

This is the most common way developers use console.log() in real code.

console.log("Hello World");
console.log(1, 2, 3);
console.log("count", 42);
console.log({ name: "John", age: 30 });

This produces output like:

Hello World
1 2 3
count 42
{ name: "John", age: 30 }

Parameters

The key parameters of console.log() include:

ParameterExplanation
valueA single value to print. Can be a string, number, boolean or any primitive type.
value1, value2, ...Multiple values printed on the same line, separated by spaces.
objectA JavaScript object. Displayed as an expandable structure in most browsers.
arrayAn array of values. Logged as a list, often with indexed entries.
label, valueA label followed by a value. Useful for readable, descriptive logs when debugging.

Note thatconsole.log() accepts one or more arguments of any type. Each argument is printed in the order it’s passed.

Return value

console.log() always returns undefined, since its only purpose is to display information in the console rather than produce output for further computation.

Where console.log output appears

When you call console.log(), JavaScript sends the message to whichever logging surface the current environment provides. In a browser it shows up in the DevTools Console, but Node.js prints to standard output (stdout) in your terminal.

We need the browser’s Console panel to see our logs, and we can get to the panel by opening DevTools (F12 or Cmd + Option + I on macOS) and selecting the Console tab. All console.log() output will appear here.

Google Chrome Developer Tools open to the Console tab, showing the console interface with a filter bar, log-level controls, and navigation tabs including Elements, Sources, Network, Performance, Memory, and Application.
The Console tab of the Google Chrome browser’s Developer Tools.

Browser compatibility

console.log() is available in all modern browsers and JavaScript environments. It has been supported for many years and works reliably across all major engines.

Browser groupEarliest known support
Chrome / Chromium-based (Chrome, Edge, Opera, Brave, Vivaldi)Chrome 2+
FirefoxFirefox 4+
Safari / WebKit (Safari, iOS Safari)Safari 4+
Internet Explorer / Legacy EdgeIE9+, Edge 12+
Node.jsNode.js 0.1+

Now let’s branch out a little and analyze the different types of data that you can log in your day-to-day.

Logging different types of data

When using console.log(), you’ll find that different types of values appear in the console in different ways. Knowing how strings, objects, arrays, DOM nodes and complex structures appear in DevTools helps us quickly spot mistakes and confirm our assumptions while debugging.

Strings and variables

console.log() can print text, numbers and variable values. We can also add a short label to make logs easier to read.

When logging multiple values, note that the console prints them in order on the same line. This is the simplest way to confirm values while writing or testing small bits of code.

const message = "Hello";
const total = 5;

console.log(message);
console.log(total);
console.log("Total:", total);
Hello
5
Total: 5

Objects and arrays

Another key strength of console.log() is that it displays objects and arrays in a clean, interactive format, making it easy to inspect nested data and verify its shape.

const user = { name: "John", age: 30 };
const items = ["Apple", "Orange"];

console.log(user);
console.log(items);
console.log("user:", user);
{ name: "John", age: 30 }
[ "Apple", "Orange" ]
user: { name: "John", age: 30 }

DOM elements

console.log() can also print DOM nodes. These appear as live, interactive elements in the console.

This helps us confirm that our selectors match the right element and lets us inspect attributes, children, and current state directly from DevTools.

const button = document.querySelector("button");
console.log(button);

The output typically shows:

<button>Click me</button>

Complex values

console.log() allows us to expand complex objects, nested structures and functions so we can explore them interactively.

It’s important to remember that modern browsers present these values in a structured, interactive format. This is especially helpful when dealing with API responses or larger data structures where we need to verify nested values quickly.

const data = {
  user: { name: "John", age: 30 },
  items: ["Apple", "Orange"],
  active: true,
  compute: () => 42
};

console.log(data);
{
  user: { name: "John", age: 30 },
  items: [ "Apple", "Orange" ],
  active: true,
  compute: ƒ
}

Console logging levels (log, info, warn, error, debug)

The console provides multiple logging levels to help us separate regular messages from warnings, errors, and debugging details.

All levels appear in the Console tab, but each one has its own visual style. This is a great help when we want to root out issues during development.

MethodDescription & common use case
console.log()General-purpose output provides regular messages, values, and checkpoints in our code.
console.info()Informational updates generate non-critical status messages or helpful notes.
console.warn()Warnings highlight behavior that isn’t breaking but may cause issues.
console.error()Errors show failures or exceptions that require immediate attention.
console.debug()Debug details display internal information, only when debug-level logs are enabled.
console.log('This is a log message');
console.info('This is an info message');
console.warn('This is a warning message');
console.error('Err!!! It is an error message');
console.debug('Let us debug this!');

Here is the output in the Firefox browser:

Image
The Firefox browser offers various different logging methods.

Formatting and styling console.log output

It probably goes without saying that we can debug our apps far more quickly when the logs are readable. Thankfully, JavaScript gives us several ways to make console output easier to interpret.

Apart from using simple labels for values, which we covered earlier, we can also:

  • Insert dynamic values into formatted strings with substitution specifiers.
  • Highlight important parts of a message using CSS styling.
  • Make complex or repetitive output easier to scan with structured formatting.
  • Improve log clarity without changing how our code behaves.

These techniques help us spot key information quickly and keep our logs organized when working on larger applications.

Formatting console log messages

console.log() supports format specifiers that let us insert values into a formatted string. This makes logs easier to read, especially when we print multiple values in a specific order.

SpecifierDescription
%sFormats a value as a string
%dFormats a value as an integer
%fFormats a value as a floating-point number (default: 6 decimals)
%oPrints a DOM element
%OPrints an object representation
%%Prints a literal percent sign

A clean substitution example:

const name = "John";
const tasks = 7;
const ratio = 0.75;

console.log(
  "User: %s | Tasks: %d | Completion: %f",
  name,
  tasks,
  ratio
);

Output:

User: John | Tasks: 7 | Completion: 0.750000

This keeps logs structured and predictable, useful when printing multiple values or building consistent debugging output.

Styling console output

We can style console messages using the %c specifier.

This lets us add colors, backgrounds, or font styles to our logs.

Styled logs make important information easier to spot when debugging larger applications or scanning long sequences of messages.

The first %c applies the CSS rules that follow it, and additional %c markers let us switch styles mid-message.

Here’s an example that shows both styling and value substitution:

console.log(
  '%c I have %d %s',
  'color: green; background:black; font-size: 20pt',
  3,
  'Bikes!'
)

Output:

Image

And here’s an example using two different styles in one log:

console.log(
  "%cUser loaded:%c John Doe",
  "font-weight: bold; color: #333;",
  "color: blue;"
);

Using %c helps us visually separate labels from values, highlight dynamic data, and create logs that stand out during debugging.

Image

Managing and organizing console.log output

As our applications grow, the console can quickly fill with clutter. Realising this, JavaScript gives us a proper toolkit to keep logs clear, focused and easy to work with.

Here are some tools you can use to navigate heavy output more efficiently and stay focused while debugging.

  • Filter logs by text or level to surface only the messages we care about.
  • Group related output to keep debugging steps visually structured.
  • Inspect structured data with tools like console.table() and console.dir().
  • Trace execution paths to understand how we reached a specific point.
  • Control console behavior so logs persist, update live, or stay visible across reloads.

Filtering console.log output

When the console fills with messages, filtering helps us quickly narrow down what matters.

Browsers provide two main filtering tools:

  • Text filtering: typing in the filter box shows only logs that match the text we enter.
  • Level filtering: selecting specific levels (log, info, warn, error, debug) hides everything else.

Both features make it easier to focus on relevant output and ignore noise, especially in larger applications.

In the image below, we’ve filtered messages matching the text status code.

Image
Filter messages using free-flow texts.

We can also filter the messages by levels using the drop-down in the console tab.

Google Chrome DevTools Console with log-level filtering enabled, showing only error messages. The log-level dropdown menu is open with options for Default, Verbose, Info, Warnings, and Errors, while several HTTP 404 and network request errors are displayed in the console.
Select one or more log levels to filter the messages.

Grouping console.log messages

When many logs come from the same feature or flow, keeping them loose can get confusing. Grouping related messages makes it easier to see which logs belong together in the console.

JavaScript provides a small set of console grouping methods:

  • console.group(label) starts a new group. All following logs are indented under this label.
  • console.groupCollapsed(label) does the same, but the group starts collapsed.
  • console.groupEnd() closes the most recent open group.

Here is an example:

console.group('Testing my calc function');
console.log('adding 1 + 1 is', 1 + 1);
console.log('adding 1 - 1 is', 1 - 1);
console.log('adding 2 * 3 is', 2 * 3);
console.log('adding 10 / 2 is', 10 / 2);
console.groupEnd();

And here is the output:

Chrome DevTools Console showing the use of console.group() to organize related log messages under a collapsible section labeled “Testing my calc function,” with grouped outputs for several arithmetic operations displayed beneath it.
All logs are grouped together.

We can create as many groups as we want. It’s best to give each group a clear label, so we can quickly recognize which part of the code the logs belong to.

Preserving logs across reloads

By default, the console clears itself every time we reload or navigate to a new page. This makes debugging frustrating when we’re trying to track down an issue that happens during navigation.

Most browsers provide a simple fix: enable Preserve log in the Console settings.

  • Open the Console.
  • Click the gear icon to open settings.
  • Check Preserve log.

This keeps all console output visible across reloads, which is especially helpful when debugging redirects, authentication flows, or page transitions.

Turn on the setting to preserve the logs between page reloads.

Advanced console logging techniques

Once we are comfortable logging basic values, we can add a few extra bits of kit that make debugging much faster.

Modern browsers provide tools that help us inspect data, measure performance and understand how our code executes in real time. Here are some of the most common:

Method / FeatureWhat it helps us do
console.trace()Show a full stack trace to understand how execution reached a specific point.
console.table()Display arrays or objects in an easy-to-scan table format.
console.dir()Inspect an object’s properties in a structured, interactive list.
Live ExpressionsPin an expression in DevTools and watch its value update in real time.
Store as global variableSave logged values as temporary globals for deeper inspection.
console.time() / timeEnd()Measure how long a block of code takes to run.
Multi-line Console InputWrite multi-line commands using Shift + Enter before executing.
$0, $_, $, $$ utilitiesQuickly reference selected DOM nodes or repeat previous outputs.
clear()Clear all console output instantly for a clean debugging view.

Tracing execution with console.trace()

console.trace() prints a full stack trace showing how the code reached its current point. This is ideal when we want to trace a bug back to a particular function call.

In the following code snippet, we have a trace inside the inner() function, defined and invoked inside the outer() function.

function outer() {
  function inner() {
    console.trace();
  }
  inner();
}

outer();

You’ll see a list of function calls (inner → outer → global scope), which helps us debug unexpected execution paths.

Image

A stack trace is logged with all the function invocation traces.

Measuring performance with console.time()

Sometimes we need to understand how long a piece of code takes to run, especially when comparing approaches or checking for bottlenecks.

The console provides two simple tools for this:

  • console.time(label) starts a timer.
  • console.timeEnd(label) stops it and prints the elapsed time.

These methods give us a quick way to benchmark operations directly in the browser without adding extra tooling.

Here’s an example that measures how long it takes to repeatedly read a property from an object inside a loop.

function testPerformance() {
  const users = [
    { firstname: "Tapas", lastname: "Adhikary" },
    { firstname: "David", lastname: "Williams" },
    { firstname: "Brad", lastname: "Crets" },
    { firstname: "James", lastname: "Bond" },
    { firstname: "Steve", lastname: "S" }
  ];

  const getLastName = (user) => user.lastname;

  console.time("loopTime");

  for (let i = 0; i < 1_000_000; i++) {
    getLastName(users[i % users.length]);
  }

  console.timeEnd("loopTime");
}

The output will be as follows:

loopTime: 12.45ms

Displaying data as tables with console.table()

We can log complex data structures as tabular data into the console. When doing so, the console.table() method lets us represent complex JSON data in the row-column fashion.

Image
The table() method shows the user’s data in a table format.

By default, the table() method will display all elements in the rows. We can restrict this display with the help of an optional columns parameter.

// Will show only the value of "name" attributes in each row
console.table(users, ["name"]); 

Inspecting objects with console.dir()

console.dir() displays an object as an interactive list of properties, making it easier to inspect nested structures.

While console.log() also shows objects, console.dir() focuses purely on the object itself, not on how the browser might render it.

console.log(["Apple", "Orange"]);
console.dir(["Apple", "Orange"]);
  • console.log() prints the array in a compact inline format.
  • console.dir() shows a tree-like, expandable structure, including the object’s type and prototype.

This is especially useful when debugging complex data, DOM elements or deeply nested objects.

The output:

Image
Console.log
Image
Console.dir

DevTools features that enhance console work

As we mentioned right at the top,console.log() is a foundational tool. It provides a great entry-point to debugging, but the browser’s DevTools will make it into a proper dashboard.

Modern consoles offer powerful features like interactive object inspection, filtering, log grouping, and persistent logs that can expedite and optimize your workflow and make your logs easier to read. These are the ones you should definitely add to your repertoire.

Creating live console expressions

Live expressions let us monitor a JavaScript value in real time directly inside DevTools.

They’re useful when we want to watch a variable, DOM state, or function result update without retyping anything.

  • Open DevTools and switch to the Console panel.
  • Click the eye icon at the top (Live Expression button).
  • Type any JavaScript expression we want to monitor (for example: window.scrollY, app.state, cart.length).
  • Press Enter to pin it.

The value now updates automatically whenever the underlying data changes.

The expression builder. Note: you can pin expressions
The expression builder. Note: you can pin expressions

Storing values as global variables

In real-world programming, we’re going to deal with a big chunk of JSON objects in response to API calls and we might want to isolate a tiny portion for granular analysis and improvement.

The console tool allows us to save any portion of the JSON object as a Global Temporary Variable. We can use this variable later in the console panel for computations.

Check out the example below. Note that we’re saving the users array as a temporary variable and using it further.

A handy way to deal with the massive JSON response.
A handy way to deal with the massive JSON response.

Multi-line console messages

Writing multi-line code directly into the console is easy once we know the shortcuts.

Here’s how to do it:

  • Type a line of code.
  • Press Shift + Enter to start a new line without running the code.
  • Repeat as needed to build a multi-line expression.
  • Press Enter (alone) to execute everything at once.

This makes it much easier for us to test longer snippets or prototype logic directly inside DevTools.

Multi-Line expressions in the console panel.
Multi-Line expressions in the console panel.

JavaScript console utilities

The console tool has several utility APIs to select, inspect, and monitor DOM elements. Note that we can only run these utility commands from the dev tools console panel: we can’t run them with external scripts.

$0: Reference a node

The $0 utility command returns the recently selected node in the Elements panel, so that we can refer to it and perform further debugging and computations.

Check out the example below. It shows how we select and use a DOM element from the Elements panel in the Console panel.

$0 command to reference the latest node.
$0 command to reference the latest node.

$_: Refer to previous execution output

The $_ utility command returns the value of the expression we executed recently. Take a look at the image below to understand how to use the command in the console.

$_ command to refer to previous execution output
$_ command to refer to previous execution output

$: Query selector

The $ utility command works like document.querySelector(), returning the reference to the first DOM element with the specified CSS selector.

The example below shows the usage of the $ command to select the first image DOM element.

$ command works as a query selector
$ command works as a query selector

$$: Query selector all

The $$ utility command works like document.querySelectorAll() to return an array of elements that match the specified CSS selector. The example below shows the usage of the $$ command to select all DOM elements that represents images.

$$ command selects query selector for all matching tags
$$ command selects query selector for all matching tags

clear() method

The clear() method will clear the console.

When console.log isn’t enough: remote logging

Everything we’ve covered so far helps us debug issues in our own browser.

But real-world problems often happen on our users’ devices, sometimes on the other side of the world. To understand those issues, we need a way to collect logs remotely.

This is where Bugfender comes into its own (if you don’t mind us saying so). Bugfender enables developers to gather logs from customer devices remotely, so we get a comprehensive view of an application’s performance even when the user is on a different continent.

Bugfender is available as a Javascript package you can integrate in your Javascript application, and provides integrations with multiple frameworks. Here are some examples:

https://github.com/bugfender/BugfenderSDK-JS-Sample
https://github.com/bugfender/BugfenderSDK-Vue-Sample
https://github.com/bugfender/BugfenderSDK-Angular-Sample

You can also find us on GitHub here.

Also while we’re on the subject, if you want to improve the overall quality of your Javascript application by developing a robust error handling methodology, we’ve got a dedicated post which you can find here.

To conclude

We hope this article helps you, both to get better information from your users and to log these insights more accurately.

But there’s loads more we can discuss when it comes to dev tools. While the console panel is powerful, it is still just a drop in the ocean of possibilities our browser offers, specifically around Developer Tools and JavaScript debugging.

Want to explore the topic further? Here’s a great piece to read next.

How to Use the Javascript Debugger

Expect The Unexpected!

Debug Faster With Bugfender

Start for Free
blog author

Aleix Ventayol

Aleix Ventayol is CEO and co-founder of Bugfender, with 20 years' experience building apps and solutions for clients like AVG, Qustodio, Primavera Sound and Levi's. As a former CTO and full-stack developer, Aleix is passionate about building tools that solve the real problems of app development and help teams build better software.

Join thousands of developers
and start fixing bugs faster than ever.