Context Menu Browser Extensions: Building and Using Right-Click Customization

The right-click menu is one of the oldest customization surfaces in the browser, and one of the most underused. A well-designed context menu extension turns a five-step workflow — select text, copy, switch tabs, open a search, paste, hit enter — into a single click. The API is small, the permissions implications are larger than they look, and the security review you should do before installing one is more important than most users realize.

Palancar’s archive included a long-running context search extension hosted under /extensions/contextsearch/ in earlier years. The contextual search pattern it implemented is still the canonical example for this category, and the lessons from maintaining it shape this guide.

The contextMenus API: A Working Overview

The Chrome and Firefox contextMenus API (Firefox also exposes menus, a superset) lets an extension add items to the right-click menu. The shape is straightforward:

chrome.runtime.onInstalled.addListener(() => {
  chrome.contextMenus.create({
    id: "lookup-selection",
    title: "Look up '%s'",
    contexts: ["selection"]
  });
});

chrome.contextMenus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === "lookup-selection") {
    const url = `https://example.com/search?q=${encodeURIComponent(info.selectionText)}`;
    chrome.tabs.create({ url });
  }
});

Three things in this snippet are worth understanding:

  • contexts controls where the menu item appears. Options include "all", "page", "selection", "link", "image", "video", "audio", "editable", "frame", and "action". Using "all" when you mean "selection" is the most common mistake; it clutters the menu everywhere and gives the impression the extension does more than it does.
  • %s in title is substituted with the selected text. It is the only template placeholder the API supports.
  • info.selectionText is the text the user selected, passed to the click handler. The extension never needs to inject a content script to retrieve it.

That last point is the security crux: a context menu extension that only acts on user selection does not need broad host permissions. The selection text is delivered to the background context directly.

Permission Requirements: The Important Distinction

There are two ways to build a context menu extension, and the permission profiles are very different.

Pattern A: User selection only, navigate to a URL. The extension declares "contextMenus" and nothing else (or "contextMenus" plus "tabs" if it needs to open in a specific tab arrangement). No host permissions. No content scripts. The extension cannot read any page content; it can only act on what the user explicitly selected.

This is the minimal-permission pattern, and it is the right choice for any extension whose function is “send the user’s selection to a URL.” Search, translate, dictionary lookup, “open in another search engine,” and most lookup-style tools fit here.

Pattern B: Read or modify page content. The extension declares host permissions ("<all_urls>", "https://*/*", or specific origins) and injects content scripts to read the DOM, manipulate the page, or extract data beyond the selection.

This is required for use cases like “extract all images on the page,” “copy the page as Markdown,” or “modify the selected element.” It is also where 90% of the security risk in this category lives. An extension with <all_urls> host permission can read every page you visit, including your bank, your email, and any internal tools you use at work.

When reviewing a context menu extension, the first question is always: does its functionality actually require host permissions, or could it be built with the minimal-permission pattern? If a search-style extension requests <all_urls>, that is a yellow flag — not necessarily malicious, but worth a closer look at what else it does.

Use Cases That Justify the API

The context menu pattern works well for:

  • Search and lookup. Send selected text to a search engine, dictionary, knowledge base, internal docs site, or specialized search (legal, medical, code search).
  • Translation. Translate selection in place or open it in a translation service.
  • Copy formats. Copy as plain text (stripping formatting), copy as Markdown, copy as a citation, copy a link’s URL.
  • Workflow shortcuts. Send the current page URL to a read-later service, a bookmarking tool, or an internal documentation system.
  • Developer utilities. Open the current URL in an alternative browser, decode a selected base64 string, format selected JSON, look up an error message.

It works poorly for anything that needs to be invoked frequently or quickly — context menus require two clicks (right-click, then select) and a deliberate intent. Keyboard shortcuts via chrome.commands are a better fit for frequent actions.

Performance Considerations

Context menus are not free, and a poorly-built extension can degrade the right-click experience across every page.

Menu construction time matters. Create menu items in onInstalled or onStartup, not on every page navigation. Re-creating items on every page load is a common bug that adds latency to navigation and, in some browser versions, leaks menu items.

Avoid contexts: ["all"] unless you mean it. Every item with contexts: ["all"] is built and rendered on every right-click, on every page, in every frame. A handful of these from different extensions is the main reason some users see ten-item right-click menus.

Service worker cold starts apply. In MV3, the click handler runs in the service worker. If the worker has been terminated, the first right-click after a long idle period will be slightly slower than subsequent ones as the worker spins up. See our MV3 migration guide for the broader service worker lifecycle.

Submenu depth costs. Chrome supports nested submenus, but each level adds visual latency on hover. Keep menus flat unless grouping is genuinely useful.

Cross-Browser Compatibility

The API is one of the more consistent ones across the major browsers, but there are differences:

  • Chrome and Edge use chrome.contextMenus.
  • Firefox supports browser.contextMenus and the superset browser.menus, which adds an onShown event (lets you update menu items just before they appear) and an onHidden event. These Firefox-only events enable patterns like “show the current selection in the menu title with custom formatting” that Chrome cannot match.
  • Safari supports the API through its Web Extension conversion, with some restrictions on dynamic updates and a slightly different visual integration.
  • Mobile Chrome and Mobile Firefox generally do not expose the context menu API to extensions. Plan for desktop-only.

For the broader picture of where the WebExtensions surface aligns and diverges, see our WebExtensions API cross-browser compatibility guide.

Reviewing a Context Menu Extension Before Installing

The security review you should do is short and worth the time.

  1. Read the permissions list before installing. “Read and change all your data on all websites” is the wording for <all_urls> host permission. If a context-menu-only extension requests this, ask why. A pure lookup extension does not need it.
  2. Check the manifest if it is open source. The permissions and host_permissions arrays tell you exactly what the extension can do. If the source is on GitHub, the manifest is two minutes of reading.
  3. Check what content scripts run, if any. A content script in an MV3 extension is declared in the manifest and can be inspected. If a search-style extension is injecting scripts into every page, that is worth understanding.
  4. Check the update history. Extensions that change ownership or have sudden permission expansions in their update history are the highest-risk category. A context menu extension that has been stable for years and is suddenly requesting new permissions is a flag.
  5. Prefer extensions where the action is one-shot and observable. When you right-click and pick the menu item, you can see what happens. Extensions that act on every page load — even context menu extensions that secondarily inject scripts — are harder to audit by observation.

The historical lesson from running a context search extension at scale: the most common abuse pattern is not malicious initial code, it is acquisition. A small, useful extension with a few thousand users gets bought by a less scrupulous owner, the next update quietly adds tracking or affiliate link rewriting, and the original permission scope is broad enough to allow it. Pattern-A extensions (no host permissions) are largely immune to this attack because there is nothing the new owner can do with the permission set. Pattern-B extensions are not.

A Minimal Reference Implementation

A complete, minimum-permission context search extension manifest looks like this:

{
  "manifest_version": 3,
  "name": "Example Context Search",
  "version": "1.0.0",
  "permissions": ["contextMenus"],
  "background": {
    "service_worker": "background.js"
  },
  "icons": {
    "48": "icon-48.png",
    "128": "icon-128.png"
  }
}

No host permissions. No content scripts. No optional permissions. The extension can add menu items, receive click events with the user’s selection, and open new tabs. That is the entire surface, and for any lookup-style use case, it is enough.

FAQ

Why does my context menu item show up on pages where I don’t want it? Almost always because contexts was set to "all" or omitted (the default depends on the browser). Set it explicitly to "selection", "link", "image", or whichever subset you actually want.

Can I add a context menu item that only appears for specific URLs? Yes — the documentUrlPatterns and targetUrlPatterns properties on create restrict items by URL. Firefox additionally supports viewTypes and richer pattern matching through the menus.onShown event.

Does a context menu extension need host permissions to read the selected text? No. info.selectionText is delivered to the click handler by the browser. Host permissions are only needed if you want to read content the user did not explicitly select.

Can I change menu items dynamically based on what the user right-clicked? In Firefox, yes — use menus.onShown to update items just before display. In Chrome, you can update items at any time with chrome.contextMenus.update, but there is no event that fires when the menu is about to open. The Firefox-only pattern is more flexible.

Is the context menu still the right surface for these actions in 2026? For deliberate, infrequent actions on selected content, yes. For frequent actions, keyboard shortcuts via chrome.commands or extension action popups give faster access. Context menus remain the best fit for “I have selected this thing and I want to do one of several things with it” — a use case nothing else covers cleanly.