ScreenshotNeo

BlogHow-to

How to Uninstall a Chrome Extension with Puppeteer

Find an extension by ID with Puppeteer, remove it with its browser API, and handle launch configuration and common errors.

By the ScreenshotNeo team4 October 20266 min read

Use Puppeteer’s extension API: get the map from browser.extensions(), look up the extension by its ID, then call browser.uninstallExtension(extensionId). You do not need to automate chrome://extensions. The removal method takes a string ID and returns a promise that resolves when the operation completes. Puppeteer’s Chrome Extensions guide documents this workflow.

1. Install Puppeteer

This example uses Node.js with the puppeteer package, which downloads a compatible browser as part of its normal installation:

npm install puppeteer

Save the following as uninstall-extension.mjs and run it with node uninstall-extension.mjs. Replace EXTENSION_ID with the ID you want to remove.

2. Find and uninstall the extension

import puppeteer from 'puppeteer';

const extensionId = 'EXTENSION_ID';
const browser = await puppeteer.launch({
  enableExtensions: true,
});

try {
  const extensions = await browser.extensions();
  const extension = extensions.get(extensionId);

  if (!extension) {
    const installed = [...extensions.entries()]
      .map(([id, item]) => `${item.name} (${id})`)
      .join('\n');
    throw new Error(
      `Extension ${extensionId} was not found. Installed extensions:\n${installed || '(none)'}`,
    );
  }

  console.log(`Removing ${extension.name} ${extension.version} (${extensionId})`);
  await browser.uninstallExtension(extensionId);
  console.log('Extension uninstalled.');
} finally {
  await browser.close();
}

browser.extensions() returns a map keyed by extension ID. The values expose properties such as name and version. Looking up the ID first prevents a missing or mistyped ID from being treated as a successful removal.

3. Make sure extensions are enabled at launch

Puppeteer passes --disable-extensions by default. If the browser starts without extensions enabled, the inventory may not include the extension you expect. Set enableExtensions: true when you need to work with extensions. Puppeteer documents this option in its LaunchOptions reference and discusses the default behavior in its troubleshooting guide.

Uninstall an extension loaded from a local directory

If your test loads an unpacked extension at launch, pass its directory in enableExtensions. The directory is how the extension is loaded; once loaded, use the returned extension map to find its ID and uninstall it.

import puppeteer from 'puppeteer';
import path from 'node:path';

const pathToExtension = path.join(process.cwd(), 'my-extension');
const browser = await puppeteer.launch({
  enableExtensions: [pathToExtension],
});

try {
  const extensions = await browser.extensions();
  const match = [...extensions.entries()].find(
    ([, extension]) => extension.name === 'My Extension',
  );

  if (!match) {
    throw new Error('My Extension was not found in the extension inventory');
  }

  const [extensionId, extension] = match;
  console.log(`Removing ${extension.name} (${extensionId})`);
  await browser.uninstallExtension(extensionId);
} finally {
  await browser.close();
}

Matching by name is useful when the ID is not already known, but names need not be unique. For repeatable automation, record the ID returned by installation or identify the extension using additional expected properties.

Install at runtime, then remove by ID

Puppeteer also supports enabling extension support and installing an unpacked extension while the browser is running. installExtension() returns the ID to pass to uninstallExtension().

import puppeteer from 'puppeteer';
import path from 'node:path';

const pathToExtension = path.join(process.cwd(), 'my-extension');
const browser = await puppeteer.launch({ enableExtensions: true });

try {
  const extensionId = await browser.installExtension(pathToExtension);
  const extension = (await browser.extensions()).get(extensionId);

  console.log(`Installed ${extension?.name ?? extensionId}`);
  await browser.uninstallExtension(extensionId);
} finally {
  await browser.close();
}

These are separate operations: loading or installing supplies the extension, while uninstallation removes it by ID. See the official extension guide for both documented loading patterns.

4. Choose the right launch configuration

Situation Configuration What to know
Extensions must be active in the browser enableExtensions: true Prevents Puppeteer’s default extension-disabling arguments.
Load one or more unpacked extensions on startup enableExtensions: [path1, path2] Pass paths to the unpacked extension directories.
Install an unpacked extension during the session enableExtensions: true, then browser.installExtension(path) Save the returned ID for lookup or removal.
Use a particular browser data directory userDataDir: '/path/to/profile' This selects a user data directory; it does not itself uninstall an extension.

For exact option types and current behavior, consult the LaunchOptions reference. Avoid changing arbitrary browser flags to solve extension issues when the documented enableExtensions option applies.

5. Troubleshoot common problems

Symptom Likely cause Fix
The extension is missing from browser.extensions() Extensions were disabled at launch, the extension was not loaded into this browser, or the ID belongs to another profile. Launch with enableExtensions: true or pass the unpacked path in an array. Check the returned map before uninstalling.
extensions.get(id) returns no value The ID is incorrect or the extension is not present in this browser session. Print the map’s IDs, names, and versions, then use the exact key from that map.
Chrome fails to launch when extensions are enabled Puppeteer’s default disable flag can conflict with policies that enforce extensions, as described in the official troubleshooting guide. Use the documented enableExtensions: true launch option and review the launch error and applicable browser environment.
An unpacked extension does not load The path may not identify the extension directory, or it may not be included in the launch option or runtime install call. Check the path and use enableExtensions: [path] or installExtension(path).
Code tries to remove an extension through a settings page The browser UI is being automated for an operation Puppeteer exposes directly. Use browser.uninstallExtension(id) instead of UI clicks.

6. Reliability, performance, and cost considerations

  • Use the ID from the same browser session. Enumerate extensions after launching the browser you intend to modify. Do not assume an ID from another profile or run identifies an installed extension in this session.
  • Make cleanup predictable. Put browser.close() in a finally block so the browser is closed even when lookup or removal throws.
  • Prefer direct API calls. Looking up the map and calling the uninstall method avoids timing-sensitive settings-page navigation and UI interactions.
  • Keep scope in mind. This API call removes the extension from the running browser context. The cited documentation does not promise removal of every piece of extension-related data or cleanup of external user profiles.
  • Plan runtime cost around browser work. This is local browser automation; the cited Puppeteer material gives no performance benchmark or per-operation price. Browser startup, extension loading, and the work your test performs determine the elapsed time and compute resources.

Or skip the browser setup

If the task is to capture a webpage rather than automate extension removal, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF; the API documentation is at ScreenshotNeo docs.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
  • Cookie banners are accepted like a visitor and removed, along with supported newsletter popups and chat widgets, before the shot; each step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
  • An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
  • The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Sign up free for 1,000 screenshots a month, no card required.

FAQ

Do I need to navigate to chrome://extensions?

No. Puppeteer documents browser.uninstallExtension(id) as the direct removal method.

What does uninstallExtension() return?

It returns Promise<void>. Await it so your script waits for the operation to finish.

Can I remove an extension if I only know its name?

List the extension map and inspect its values, then use the associated ID. A name may not uniquely identify an extension, so check the ID and other properties where needed.

Does userDataDir remove extensions?

No. It selects a browser user data directory. Removal is performed with browser.uninstallExtension(id).