Chrome Extension History API: Access and Manage Browsing History

19 min read

Chrome Extension History API: Access and Manage Browsing History

Chrome Extension History API: Access and Manage Browsing History

The Chrome Extension History API represents one of the most powerful capabilities available to extension developers. This comprehensive API enables you to build sophisticated browsing history manager extensions that can search, analyze, and manipulate a user’s browsing data. Whether you’re creating a personal history search tool, an analytics dashboard, or a productivity-focused extension that helps users revisit important pages, the chrome.history namespace provides the functionality you need.

This guide walks you through every aspect of the Chrome History API, from basic concepts to advanced implementation patterns. You’ll learn how to request proper permissions, query history items, add custom entries, delete records, and handle the asynchronous nature of history operations. By the end of this article, you’ll have the knowledge to build robust history management extensions that enhance user productivity and provide valuable insights into browsing patterns.


Understanding the Chrome History API

The chrome.history API is part of Chrome’s extension APIs that provides programmatic access to the user’s browsing history. This powerful interface allows extensions to read, search, add, and delete history entries, enabling a wide range of functionality from simple history viewers to complex analytics tools.

Before diving into implementation, it’s essential to understand what the History API can and cannot do. The API provides read access to all visited URLs, along with metadata such as visit times, visit counts, and the referring page. You can search through history using various criteria, including text queries, time ranges, and URL patterns. The API also supports adding new history entries and deleting existing ones, giving you full control over the history database.

However, the History API operates with certain limitations and privacy considerations. Users must explicitly grant permission through the manifest file, and they can revoke this permission at any time. The API only provides access to the Chrome browser’s history—it doesn’t extend to other browsers or private browsing sessions unless specifically configured. Understanding these boundaries helps you design extensions that respect user privacy while delivering valuable functionality.


Setting Up Permissions in Manifest V3

Before using the chrome.history API, you must declare the appropriate permission in your extension’s manifest file. This is a critical step that enables your extension to access the user’s browsing history.

For Chrome Extensions using Manifest V3, add the “history” permission to your manifest.json file:

{
  "name": "History Manager Extension",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "history"
  ],
  "host_permissions": [
    "<all_urls>"
  ]
}

The “history” permission grants access to the chrome.history API methods. Additionally, if your extension needs to interact with specific websites or perform actions on visited pages, you may need to include appropriate host permissions. The host permission “" allows your extension to access content on any webpage, which is often necessary for extensions that analyze or interact with page content.

It’s worth noting that requesting the history permission triggers a specific warning during the Chrome Web Store review process. You’ll need to provide a clear explanation of why your extension requires history access and how it benefits users. Extensions that misuse history data or fail to provide adequate justification may be rejected or restricted.


Querying History Entries

The cornerstone of the chrome.history API is the search functionality, which allows you to retrieve history entries based on various criteria. The chrome.history.search() method is asynchronous and returns a promise that resolves to an array of HistoryItem objects.

Here’s how to perform a basic history search:

chrome.history.search({
  text: '',
  maxResults: 100,
  startTime: 0
}, function(results) {
  results.forEach(function(item) {
    console.log('URL:', item.url);
    console.log('Title:', item.title);
    console.log('Visit Count:', item.visitCount);
    console.log('Last Visit:', new Date(item.lastVisitTime));
  });
});

This example retrieves the most recent 100 history entries. The text parameter supports search queries—you can search for specific URLs, page titles, or keywords. Setting text to an empty string returns all entries within the specified time range. The maxResults parameter limits the number of returned items, while startTime filters results to visits after a specific timestamp.

Advanced Search with Time Ranges

For more targeted queries, you can combine text search with time-based filtering:

// Get history from the last 24 hours
const oneDayAgo = (Date.now() - 24 * 60 * 60 * 1000);

chrome.history.search({
  text: 'tutorial',
  startTime: oneDayAgo,
  maxResults: 50
}, function(results) {
  // Process results
  results.forEach(function(item) {
    console.log(`Found: ${item.title} - ${item.url}`);
  });
});

This pattern is particularly useful for building analytics features that show user activity over specific periods. You can easily adapt this to show weekly or monthly browsing patterns by adjusting the startTime calculation.


Understanding HistoryItem Objects

When you query history, each result is returned as a HistoryItem object containing detailed information about a visited URL. Understanding the structure of these objects helps you effectively use the data in your extension.

Properties of HistoryItem

The HistoryItem object includes the following key properties:

  • id: A unique identifier for this history entry
  • url: The URL that was visited
  • title: The page title (may be empty if not available)
  • visitCount: The number of times this URL has been visited
  • typedCount: The number of times the URL was typed directly
  • lastVisitTime: Timestamp of the most recent visit
  • visitId: ID of the most recent visit to this URL

Here’s an example of processing a HistoryItem:

function processHistoryItem(item) {
  return {
    url: item.url,
    title: item.title || 'No Title',
    visits: item.visitCount,
    lastVisited: new Date(item.lastVisitTime).toLocaleString(),
    isFrequent: item.visitCount > 10
  };
}

The title property may be empty for URLs that Chrome hasn’t yet crawled or for certain types of redirects. Your extension should handle cases where title is null or undefined gracefully.


Adding Custom History Entries

The chrome.history API allows you to programmatically add new entries to the browsing history. This functionality is valuable for extensions that want to track user interactions with external links, bookmark syncing tools, or any feature that involves navigating to URLs outside the normal browsing flow.

Using addUrl() Method

The chrome.history.addUrl() method adds a new entry to history:

function addToHistory(url, title) {
  chrome.history.addUrl({
    url: url,
    title: title
  }, function() {
    if (chrome.runtime.lastError) {
      console.error('Error adding URL:', chrome.runtime.lastError);
    } else {
      console.log('Successfully added to history:', url);
    }
  });
}

// Usage
addToHistory('https://example.com', 'Example Domain');

This method is particularly useful when your extension opens pages in ways that wouldn’t normally create history entries, such as when using the chrome.tabs.create() method with the active option set to false. By explicitly adding entries, you ensure that users can find these pages through their normal history searches.


Deleting History Entries

Managing history also involves the ability to delete entries. The chrome.history API provides multiple deletion methods to handle different use cases, from removing specific URLs to clearing all history.

Deleting Specific URLs

To remove a specific URL from history, use the deleteUrl() method:

chrome.history.deleteUrl({url: 'https://example.com'}, function() {
  console.log('URL deleted from history');
});

This removes all visits to the specified URL from the browsing history. The operation is permanent, so you should consider adding confirmation dialogs in your extension before performing deletions.

Deleting by Time Range

For bulk deletions based on time periods, use the deleteRange() method:

const oneWeekAgo = Date.now() - (7 * 24 * 60 * 60 * 1000);

chrome.history.deleteRange({
  startTime: 0,
  endTime: oneWeekAgo
}, function() {
  console.log('Deleted all history older than one week');
});

This pattern is useful for implementing privacy features that automatically clean up old history entries.

Clearing All History

To delete all browsing history, use the deleteAll() method:

chrome.history.deleteAll(function() {
  console.log('All history has been deleted');
});

This powerful method removes all entries from the user’s browsing history. As with deleteUrl(), you should provide clear confirmation dialogs before executing this operation.


Retrieving Detailed Visit Information

Beyond basic history items, you can retrieve detailed information about individual visits using the chrome.history.getVisits() method. This returns an array of VisitItem objects, each representing a single visit to a URL.

Getting All Visits for a URL

chrome.history.getVisits({url: 'https://example.com'}, function(visits) {
  visits.forEach(function(visit) {
    console.log('Visit ID:', visit.visitId);
    console.log('Visit Time:', new Date(visit.visitTime));
    console.log('Referring URL:', visit.referringVisitId);
    console.log('Transition Type:', visit.transition);
  });
});

The VisitItem object includes properties such as visitId (unique identifier for this visit), visitTime (timestamp of the visit), referringVisitId (ID of the visit that led to this one), and transition (the type of transition, such as link, typed, or bookmark).

Understanding Transition Types

The transition property describes how the user arrived at the page. Common transition types include:

  • link: The user clicked a link on another page
  • typed: The user typed the URL directly
  • bookmark: The user accessed via a bookmark
  • form_submit: The user submitted a form
  • reload: The user reloaded the page

This information is valuable for analytics extensions that want to understand user behavior patterns.


Building a Complete History Manager Extension

Now that you understand the individual components, let’s put together a complete example that demonstrates a functional history manager extension. This example showcases how to combine the various chrome.history methods into a cohesive user experience.

Background Script Implementation

// background.js - Handles history operations

// Search history with filters
function searchHistory(query, daysBack = 7) {
  const startTime = Date.now() - (daysBack * 24 * 60 * 60 * 1000);
  
  return new Promise((resolve, reject) => {
    chrome.history.search({
      text: query,
      startTime: startTime,
      maxResults: 1000
    }, (results) => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError);
      } else {
        resolve(results);
      }
    });
  });
}

// Delete history older than specified days
function cleanOldHistory(daysToKeep) {
  const cutoffTime = Date.now() - (daysToKeep * 24 * 60 * 60 * 1000);
  
  return new Promise((resolve, reject) => {
    chrome.history.deleteRange({
      startTime: 0,
      endTime: cutoffTime
    }, () => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError);
      } else {
        resolve();
      }
    });
  });
}

// Get detailed visit information
function getVisitDetails(url) {
  return new Promise((resolve, reject) => {
    chrome.history.getVisits({url: url}, (visits) => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError);
      } else {
        resolve(visits);
      }
    });
  });
}

// Message handler for popup or content scripts
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  switch (request.action) {
    case 'searchHistory':
      searchHistory(request.query, request.daysBack)
        .then(results => sendResponse({success: true, data: results}))
        .catch(error => sendResponse({success: false, error: error.message}));
      return true;
      
    case 'cleanOldHistory':
      cleanOldHistory(request.daysToKeep)
        .then(() => sendResponse({success: true}))
        .catch(error => sendResponse({success: false, error: error.message}));
      return true;
      
    case 'getVisitDetails':
      getVisitDetails(request.url)
        .then(visits => sendResponse({success: true, data: visits}))
        .catch(error => sendResponse({success: false, error: error.message}));
      return true;
  }
});
// popup.js - User interface for history manager

document.addEventListener('DOMContentLoaded', function() {
  const searchInput = document.getElementById('search-input');
  const searchButton = document.getElementById('search-button');
  const resultsContainer = document.getElementById('results');
  const clearOldButton = document.getElementById('clear-old');
  
  // Search functionality
  searchButton.addEventListener('click', function() {
    const query = searchInput.value;
    
    chrome.runtime.sendMessage({
      action: 'searchHistory',
      query: query,
      daysBack: 30
    }, function(response) {
      if (response.success) {
        displayResults(response.data);
      } else {
        console.error('Search error:', response.error);
      }
    });
  });
  
  // Display results
  function displayResults(results) {
    resultsContainer.innerHTML = '';
    
    if (results.length === 0) {
      resultsContainer.innerHTML = '<p>No results found</p>';
      return;
    }
    
    results.forEach(function(item) {
      const div = document.createElement('div');
      div.className = 'history-item';
      div.innerHTML = `
        <h3>${escapeHtml(item.title || 'No Title')}</h3>
        <p class="url">${escapeHtml(item.url)}</p>
        <p class="meta">Visits: ${item.visitCount} | Last visited: ${new Date(item.lastVisitTime).toLocaleString()}</p>
        <button class="delete-btn" data-url="${escapeHtml(item.url)}">Delete</button>
      `;
      resultsContainer.appendChild(div);
    });
    
    // Add delete handlers
    document.querySelectorAll('.delete-btn').forEach(function(btn) {
      btn.addEventListener('click', function() {
        const url = this.getAttribute('data-url');
        chrome.history.deleteUrl({url: url}, function() {
          // Remove from display
          this.parentElement.remove();
        }.bind(this));
      });
    });
  }
  
  // Clean old history
  clearOldButton.addEventListener('click', function() {
    if (confirm('Delete history older than 30 days?')) {
      chrome.runtime.sendMessage({
        action: 'cleanOldHistory',
        daysToKeep: 30
      }, function(response) {
        if (response.success) {
          alert('Old history cleared');
        } else {
          alert('Error: ' + response.error);
        }
      });
    }
  });
  
  // Helper function to prevent XSS
  function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }
});

Best Practices and Privacy Considerations

When working with the chrome.history API, following best practices ensures your extension provides value while respecting user privacy. These guidelines help you create extensions that users trust and find genuinely useful.

Request Minimal Permissions

Only request the history permission if your extension genuinely needs it. Users are increasingly cautious about granting broad permissions, and Chrome reviews applications for unnecessary access. If you only need to track specific pages your extension creates, consider using alternative approaches like storing data in extension storage.

Provide Clear Value

Your extension should clearly communicate how it uses history data. If you’re building a history search tool, make that functionality obvious in your extension’s description. Avoid hidden or unexpected uses of history data that might surprise users.

Implement Proper Error Handling

The chrome.history API operations are asynchronous and can fail for various reasons. Always implement proper error handling:

chrome.history.search({text: 'test', maxResults: 10}, function(results) {
  if (chrome.runtime.lastError) {
    console.error('History API Error:', chrome.runtime.lastError.message);
    // Handle the error gracefully
    return;
  }
  // Process results
});

Respect User Privacy

Consider implementing features that give users control over their data. Options to exclude specific sites from tracking, export history data, or set automatic deletion periods demonstrate respect for user privacy and often increase user trust.


Advanced Use Cases

The chrome.history API enables various advanced implementations beyond simple history viewing. These use cases demonstrate the API’s versatility and potential for creating sophisticated extensions.

Browsing Analytics Dashboard

Create an extension that analyzes browsing patterns and presents insights about time spent on different types of websites, most visited domains, and peak browsing hours. This requires aggregating data from multiple history queries and presenting it in meaningful visualizations.

Smart Bookmark Manager

Build an intelligent bookmarking system that automatically organizes history into collections based on visit frequency, time patterns, and content categories. Machine learning algorithms can identify important pages that users return to frequently.

History Synchronization

Implement cross-device history synchronization that allows users to access their browsing history across multiple computers. This requires careful handling of data privacy and secure transmission.

Privacy-Focused History Viewer

Create a read-only history viewer with enhanced search capabilities, visualization tools, and export options. Focus on helping users find previously visited pages quickly without modifying any data.


Conclusion

The Chrome Extension History API opens up tremendous possibilities for building powerful browsing history management tools. From basic search functionality to sophisticated analytics dashboards, understanding how to effectively use chrome.history enables you to create extensions that significantly enhance user productivity.

Remember to always request only the permissions you need, handle user data with care, and provide clear value through your extension’s functionality. The chrome.history API is a powerful tool in your extension development toolkit, and with the knowledge from this guide, you’re well-equipped to build innovative history management solutions.

As Chrome continues to evolve, so too will the extension APIs. Stay current with the latest Chrome extension documentation to discover new capabilities and best practices for working with the History API and other Chrome extension features.

No previous article
No next article