Extension Source Inspection

How to Inspect Extension Source Without Installing It

To view Chrome extension source without installing it, download the ZIP package and open the extracted files in a text editor. Start with manifest.json.

Download the extension source as a ZIP

  1. Copy the extension's public Chrome Web Store URL. Check the publisher and use our extension ID guide if two listings look alike.
  2. Paste the URL into CRXFile and click Parse extension.
  3. Check the returned details, then choose Download source .zip.
  4. Extract the archive into a new folder and open that folder in a text editor. Open HTML files as text, too.

Already have a CRX? Use a CRX-aware extractor on a copy. Renaming the file to .zip can fail because a CRX includes a header before its archive payload. CRXFile's ZIP option handles that extraction for packages it retrieves. It doesn't accept local CRX uploads.

A private or removed listing may be unavailable. CRXFile can only fetch packages the official endpoint currently exposes, and it has no historical version library.

Use manifest.json to find the entry files

Don't start with the largest JavaScript file. Open manifest.json first. Chrome requires it at the extension's root, as the manifest reference explains. Record version, then find the files Chrome loads.

If the fields are unfamiliar, our guide to reading a Chrome extension manifest explains the version fields, permissions, service worker, and content script matches using the same sample below.

We made a small Source Review Demo ZIP for this exercise. It's an original teaching sample, not a store download. Extract it and read along without installing anything. We checked its file paths and message flow on October 13, 2026, without a browser installation. Here is its full manifest:

{
  "manifest_version": 3,
  "name": "Source Review Demo",
  "version": "1.0.0",
  "permissions": [
    "storage"
  ],
  "background": {
    "service_worker": "worker.js"
  },
  "content_scripts": [
    {
      "matches": [
        "https://example.com/*"
      ],
      "js": [
        "content.js"
      ]
    }
  ],
  "action": {
    "default_popup": "popup.html"
  }
}

The manifest_version value identifies the manifest format. version identifies this sample's release. Mixing them up makes review notes confusing later.

Manifest entryWhere to read next
background.service_workerworker.js: background event and message handlers.
content_scriptscontent.js: code for pages matching https://example.com/*.
action.default_popuppopup.html, then the popup.js script it loads.
permissionsThe sample requests storage. Find the code that uses it.

Follow one feature through the scripts

In the demo, content.js reads document.title and sends a PAGE_TITLE message. Search for that exact string in worker.js. The listener checks the sender and message, then writes the title to chrome.storage.local. Finally, popup.js reads the saved value and displays it using textContent.

You can trace the whole feature on disk: page title, message, local storage, popup. Pick one feature you care about in a real package and follow it the same way. Reading every file alphabetically is a slow way to find out where a single value goes.

Chrome's content script documentation covers code that interacts with web pages. Its service worker guide explains the background entry point. Other extensions may use options pages, side panels, or scripts registered through chrome.scripting, so the manifest's static content-script list isn't always the whole story.

Check permissions against actual data use

Our Chrome extension permissions review table helps you separate API permissions, website access, and optional grants before tracing how the scripts use them.

Read permissions, host_permissions, and any optional permission fields. Compare them with the feature you traced. Our demo asks for storage and uses it to save one title. Its content script targets one example host. If a real extension requests <all_urls>, ask which feature needs access across so many sites, then look for its implementation.

Broad permissions don't establish malicious intent. Missing host_permissions doesn't establish that a package cannot interact with websites, either. Read the content-script matches and the code together. Google's permission documentation distinguishes API permissions, host access, and permissions requested later.

Search for network calls and bundled code

Use your editor's folder search for fetch(, XMLHttpRequest, WebSocket, and https://. For each result, check the destination and the data being sent. A request that retrieves public settings needs a different review from one that sends page text. Chrome's network request guide explains how extension pages and content scripts differ.

Expect false leads. A URL might be a documentation link, and a network call may hide behind a helper or a constructed string. A search with no matches isn't a clean bill of health.

Minified JavaScript is harder to follow. Format a copy in your editor, check for bundled source maps, and look for license files that identify third-party libraries. Formatting restores spacing, not the author's original variable names or comments. A downloaded ZIP contains the shipped files, which may differ from the publisher's original TypeScript or repository source.

If a public repository exists, compare its release tag and build instructions with the package version. A familiar project name alone doesn't tell you whether you're reading the code that was actually shipped.

Keep a record of what you could verify

Save the store URL, extension ID, package version, and review date with your notes. Our extension backup workflow includes a record template and checksum commands. Findings apply to that saved version.

Static inspection can show which files request access and how a visible code path handles data. It cannot establish every runtime behavior, inspect a remote server's internals, or predict the next update. If you need runtime evidence, plan a separate test in an isolated browser profile.

For an unresolved call, write down the filename, function, destination, and the question you still need answered. That gives the next reviewer somewhere concrete to start.