Building Custom Chrome DevTools Panels: A Complete Developer Guide

17 min read

Building Custom Chrome DevTools Panels: A Complete Developer Guide

Building Custom Chrome DevTools Panels: A Complete Developer Guide

Chrome DevTools stands as the backbone of modern web development, providing developers with an unparalleled debugging and development environment directly within Google Chrome. While the built-in panels like Elements, Console, Network, and Sources cover most development needs, there are countless scenarios where creating custom devtools panel extensions can dramatically improve your development workflow. Whether you need to visualize complex application state, build a specialized debugging tool for a specific framework, or create an inspector extension for analyzing custom data structures, understanding how to build custom Chrome DevTools panels opens up enormous possibilities for enhancing your development experience.

This comprehensive guide walks you through the entire process of building custom Chrome DevTools panels, from understanding the underlying architecture to implementing advanced features like cross-context communication, real-time data inspection, and seamless integration with the Chrome development environment. By the end of this tutorial, you will have the knowledge and practical skills needed to create powerful custom devtools panel extensions that integrate natively with Chrome’s developer tools.


Understanding the Chrome DevTools Extension Architecture

Before diving into implementation, it is essential to develop a solid understanding of how Chrome DevTools extensions work under the hood. The architecture is designed to provide maximum flexibility while maintaining security and performance boundaries between different execution contexts.

The DevTools Page and Panel Relationship

When you create a custom devtools panel, you are essentially creating a special type of Chrome extension that integrates directly into the DevTools environment. The relationship between devtools pages and panels is hierarchical: a devtools page serves as the container that loads when DevTools opens, while panels are the individual tabbed interfaces that users interact with inside that container.

Chrome DevTools extensions operate in a unique execution context that sits between the browser’s internal APIs and web pages. This context has access to special APIs that are not available to regular web pages or even standard Chrome extensions. The most important of these is the chrome.devtools namespace, which provides interfaces for creating panels, accessing the inspected window, and communicating with other extension components.

Communication Channels in DevTools Extensions

One of the most critical aspects of building effective custom devtools panels is understanding the various communication channels available to you. There are three primary communication pathways that you will use regularly:

The Inspected Window Connection allows your panel to interact directly with the page being inspected. Through the chrome.devtools.inspectedWindow API, you can evaluate JavaScript in the context of the page, access the DOM tree, capture console messages, and even trigger page reloads. This bidirectional connection is essential for building any debugging or inspection tool.

Message Passing Between Components enables communication between your DevTools panel and other parts of your extension, such as background scripts, popup pages, or content scripts. This uses the standard Chrome message passing API but requires careful configuration to work correctly across the various extension contexts.

The Extension Runtime provides a way to maintain state and share data between different components of your extension. You can use chrome.storage to persist user preferences, inspection results, or cached data that your panel needs to function effectively.


Setting Up Your Development Environment

Every successful Chrome extension project begins with proper project setup, and DevTools extensions are no exception. Let us walk through creating a well-structured development environment for building custom devtools panels.

Creating the Project Structure

A well-organized project structure makes development significantly easier and your extension more maintainable. Create a dedicated directory for your extension project and organize it with clear separation between different types of resources:

my-devtools-panel/
├── manifest.json
├── background.js
├── devtools/
│   ├── devtools.html
│   ├── devtools.js
│   └── panel/
│       ├── panel.html
│       ├── panel.js
│       └── styles.css
├── images/
│   ├── icon-16.png
│   ├── icon-32.png
│   ├── icon-48.png
│   └── icon-128.png
└── _locales/
    └── en/
        └── messages.json

This structure separates your DevTools-specific files into their own directory, making it easy to manage the different components of your extension. The panel subdirectory contains the UI code for your custom devtools panel, while the devtools directory holds the initialization code that runs when DevTools opens.

Configuring the Manifest File

The manifest.json file is the heart of any Chrome extension, and DevTools extensions require specific configuration to function correctly. Here is a complete Manifest V3 configuration for a custom devtools panel:

{
  "manifest_version": 3,
  "name": "Custom DevTools Panel",
  "version": "1.0.0",
  "description": "A custom Chrome DevTools panel for advanced debugging",
  "permissions": [
    "storage",
    "activeTab"
  ],
  "devtools_page": "devtools/devtools.html",
  "background": {
    "service_worker": "background.js",
    "type": "module"
  },
  "icons": {
    "16": "images/icon-16.png",
    "32": "images/icon-32.png",
    "48": "images/icon-48.png",
    "128": "images/icon-128.png"
  }
}

The critical element here is the "devtools_page" field, which tells Chrome where to find the entry point for your DevTools extension. This page will load whenever DevTools opens, and it is responsible for creating your custom panels.


Implementing the DevTools Page

The DevTools page serves as the initialization point for your extension’s integration with Chrome DevTools. This page runs in a special context that has access to the DevTools APIs, and its primary job is to register your custom panels.

Creating the DevTools HTML Page

The devtools.html file is remarkably simple because most of the logic lives in the associated JavaScript file. It serves as a container that loads your initialization script:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
</head>
<body>
  <script src="devtools.js"></script>
</body>
</html>

Registering Custom Panels

The devtools.js file contains the core logic for creating and configuring your custom devtools panels. Here is how you register a new panel using the chrome.devtools.panels API:

// Create the main panel
chrome.devtools.panels.create(
  'Custom Inspector',      // Panel title
  'images/icon-16.png',   // Panel icon
  'panel/panel.html',     // Panel HTML file
  function(panel) {
    // Panel creation callback
    panel.onShown.addListener(function(panelWindow) {
      console.log('Panel shown:', panelWindow);
    });
    
    panel.onHidden.addListener(function() {
      console.log('Panel hidden');
    });
  }
);

// Create additional panels as needed
chrome.devtools.panels.create(
  'Analytics',
  'images/icon-16.png',
  'panel/analytics.html',
  function(analyticsPanel) {
    // Configure the analytics panel
  }
);

This code registers your custom panel with Chrome DevTools, specifying the title that appears in the tab, an icon, and the HTML file that contains the panel’s content. The callback function gives you access to the panel object, which you can use to listen for visibility changes and perform other initialization tasks.


Building the Custom Panel Interface

With the DevTools page configured, you can now focus on building the actual interface that users will interact with. This involves creating the HTML structure, styling it appropriately, and implementing the JavaScript logic that makes your panel functional.

Creating the Panel HTML Structure

The panel HTML file defines the user interface that appears inside your custom tab in DevTools. It follows standard HTML5 conventions but operates within the unique context of the DevTools extension environment:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="panel-container">
    <header class="panel-header">
      <h1>Custom Inspector</h1>
      <div class="controls">
        <button id="refresh-btn" class="btn">Refresh</button>
        <button id="clear-btn" class="btn">Clear</button>
      </div>
    </header>
    
    <main class="panel-content">
      <div id="inspection-results" class="results-container">
        <p class="placeholder">Select an element to inspect</p>
      </div>
    </main>
    
    <footer class="panel-footer">
      <span id="status">Ready</span>
    </footer>
  </div>
  
  <script src="panel.js"></script>
</body>
</html>

Styling Your Panel

The CSS for your custom devtools panel should match Chrome’s built-in styling to create a seamless user experience. Chrome DevTools uses a dark theme by default, and your panel should follow this convention:

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
  font-size: 12px;
  background-color: #242424;
  color: #e8eaed;
  height: 100vh;
  overflow: hidden;
}

.panel-container {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background-color: #2d2d2d;
  border-bottom: 1px solid #3c3c3c;
}

.panel-header h1 {
  font-size: 14px;
  font-weight: 500;
}

.btn {
  padding: 4px 12px;
  background-color: #3c3c3c;
  border: 1px solid #5c5c5c;
  color: #e8eaed;
  border-radius: 3px;
  cursor: pointer;
  font-size: 11px;
}

.btn:hover {
  background-color: #4c4c4c;
}

.panel-content {
  flex: 1;
  overflow: auto;
  padding: 12px;
}

.panel-footer {
  padding: 4px 12px;
  background-color: #2d2d2d;
  border-top: 1px solid #3c3c3c;
  font-size: 11px;
  color: #9e9e9e;
}

Implementing Panel Functionality

The JavaScript file for your panel contains the core logic that makes your custom devtools panel functional. This includes communicating with the inspected page, processing data, and updating the UI.

Connecting to the Inspected Window

The most important functionality of any inspector extension is its ability to communicate with the page being inspected. Here is how you establish this connection:

// Initialize when the panel loads
document.addEventListener('DOMContentLoaded', function() {
  initializePanel();
});

function initializePanel() {
  const refreshBtn = document.getElementById('refresh-btn');
  const clearBtn = document.getElementById('clear-btn');
  const resultsContainer = document.getElementById('inspection-results');
  const statusSpan = document.getElementById('status');
  
  refreshBtn.addEventListener('click', function() {
    statusSpan.textContent = 'Refreshing...';
    refreshInspection();
  });
  
  clearBtn.addEventListener('click', function() {
    resultsContainer.innerHTML = '<p class="placeholder">Select an element to inspect</p>';
    statusSpan.textContent = 'Cleared';
  });
  
  // Listen for console messages from the inspected page
  chrome.devtools.inspectedWindow.onConsoleMessage.addListener(function(message) {
    console.log('Console message:', message);
  });
  
  // Perform initial inspection
  refreshInspection();
}

function refreshInspection() {
  // Evaluate JavaScript in the context of the inspected page
  chrome.devtools.inspectedWindow.eval(
    `({
      title: document.title,
      url: window.location.href,
      elementCount: document.querySelectorAll('*').length,
      scripts: Array.from(document.scripts).map(s => s.src).filter(s => s)
    })`,
    function(result, isException) {
      if (isException) {
        console.error('Evaluation error:', isException);
        return;
      }
      displayResults(result);
    }
  );
}

function displayResults(data) {
  const resultsContainer = document.getElementById('inspection-results');
  const statusSpan = document.getElementById('status');
  
  resultsContainer.innerHTML = `
    <div class="result-section">
      <h3>Page Information</h3>
      <p><strong>Title:</strong> ${escapeHtml(data.title)}</p>
      <p><strong>URL:</strong> ${escapeHtml(data.url)}</p>
      <p><strong>Elements:</strong> ${data.elementCount}</p>
    </div>
    <div class="result-section">
      <h3>External Scripts</h3>
      <ul>
        ${data.scripts.map(s => `<li>${escapeHtml(s)}</li>`).join('') || '<li>None</li>'}
      </ul>
    </div>
  `;
  
  statusSpan.textContent = 'Ready';
}

function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}

This code demonstrates several key patterns for building custom devtools panels. The chrome.devtools.inspectedWindow.eval() method allows you to execute JavaScript in the context of the inspected page and receive the results back in your panel. You can access the DOM, read page state, call page functions, and perform virtually any operation that you could do from the browser’s JavaScript console.


Advanced Features and Best Practices

Once you have the basics working, there are numerous advanced features you can implement to create truly powerful custom devtools panels. These features distinguish amateur extensions from professional-grade tools.

Adding Context Menu Items

Chrome DevTools allows you to add custom context menu items that appear when users right-click on elements in the Elements panel or in your own custom panels. This is incredibly useful for creating inspection workflows:

// Create a context menu item for elements
chrome.devtools.panels.elements.createSidebarPane(
  'Custom Inspector',
  function(sidebar) {
    // Set the initial content
    sidebar.setExpression('document.body', 'Body element');
  }
);

// Add custom actions to the elements panel
chrome.contextMenus.create({
  title: 'Inspect with My Tool',
  contexts: ['page', 'frame', 'selection'],
  onclick: function(info, tab) {
    // Handle the context menu action
    chrome.devtools.inspectedWindow.eval(
      'window.myCustomTool.inspect()'
    );
  }
});

Persisting State with Chrome Storage

User preferences and panel state should be persisted using the chrome.storage API rather than localStorage, as this provides better integration with Chrome’s sync functionality:

// Save user preferences
function savePreferences(prefs) {
  chrome.storage.local.set({ 'panelPreferences': prefs }, function() {
    console.log('Preferences saved');
  });
}

// Load user preferences
function loadPreferences(callback) {
  chrome.storage.local.get('panelPreferences', function(result) {
    callback(result.panelPreferences || {});
  });
}

Handling Panel Visibility

Your panel can detect when it becomes visible or hidden, allowing you to optimize resource usage and perform actions only when needed:

chrome.devtools.panels.create(
  'My Panel',
  null,
  'panel.html',
  function(panel) {
    panel.onShown.addListener(function(panelWindow) {
      // Start polling or updating when panel becomes visible
      startRealTimeUpdates(panelWindow);
    });
    
    panel.onHidden.addListener(function() {
      // Stop resource-intensive operations when panel is hidden
      stopRealTimeUpdates();
    });
  }
);

Testing and Debugging Your Extension

Proper testing and debugging is essential for building reliable Chrome DevTools extensions. Chrome provides several tools and techniques to help you identify and fix issues in your custom panels.

Using Chrome’s Internal Pages for Testing

Chrome provides internal pages that can help you understand how your extension is loading and functioning. Navigate to chrome://extensions to view your extension details, and use the “Inspect views” links to open the DevTools for your extension’s background scripts and DevTools page.

Debugging Communication Issues

When your panel is not communicating correctly with the inspected page, start by checking the console for error messages. The DevTools for your panel can be opened by right-clicking anywhere in your panel and selecting “Inspect,” which opens a separate DevTools window specifically for debugging your panel.

Common issues include CSP (Content Security Policy) restrictions blocking your eval calls, incorrect permissions in the manifest, and timing issues where your panel tries to communicate with the page before it is fully loaded.


Conclusion

Building custom Chrome DevTools panels represents one of the most powerful ways to extend Chrome’s development environment for your specific needs. Throughout this guide, we have covered the complete development lifecycle, from understanding the architecture and setting up your project structure to implementing advanced communication patterns and debugging techniques.

The key to success with custom devtools panels lies in understanding the unique execution context in which they operate, leveraging the specialized APIs that Chrome provides for DevTools extensions, and following best practices for user interface design and code organization. Whether you are building a simple inspection tool or a complex debugging environment, the principles and patterns covered in this tutorial provide a solid foundation for your projects.

As you continue to develop your custom devtools panels, remember to explore the full range of Chrome’s DevTools APIs, experiment with different communication patterns, and always consider the user experience within the broader DevTools environment. With practice, you will be able to create sophisticated extensions that seamlessly integrate with Chrome’s developer tools and significantly enhance your development workflow.


Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.

No previous article
No next article