Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The smallest useful Chrome screenshot extension needs three pieces: a Manifest V3 declaration, a user-triggered action, and a service-worker call to chrome.tabs.captureVisibleTab(). That API returns an image string for the currently visible area of a tab. Save the returned data URL with a download initiated by the extension, and request only the temporary access your feature needs.

What you are building

This example adds a toolbar button. When the user clicks it, the extension captures the active tab’s visible viewport and downloads a PNG. It deliberately does not request broad access to every site. The design uses Chrome’s activeTab permission, which grants temporary access after an explicit user invocation and does not create a permission warning.

# Preview Product Price
1 The 138 Best Chrome Extensions The 138 Best Chrome Extensions $2.99

A visible-tab capture is a viewport image, not a complete document rendering. Content below the fold is absent, and browser chrome such as the address bar is not included. A full-page image requires additional scrolling, repeated captures, and image assembly; one call cannot provide it.

Choose permissions before writing code

Use activeTab for a button-driven capture

activeTab is appropriate when the user deliberately invokes capture from the toolbar, a keyboard command, or another extension UI. The grant is temporary and scoped to the tab the user acted on. It is preferable to permanent host access when you only need to capture on demand.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When all_urls is justified

Declare all_urls only when the product genuinely needs ongoing access across sites without a fresh user invocation. Explain that need in the Chrome Web Store listing and request no broader host pattern than necessary. Do not add the tabs permission merely because you call the Tabs API; it is not required for this capture method.

Special pages and file URLs

Chrome restricts sensitive browser pages. In the special cases documented by Chrome, those pages can be captured only with activeTab. A file:// page also requires the user to enable “Allow access to file URLs” on the extension’s details page. Some internal pages remain unavailable regardless of your manifest.

Keep privileged code in the right context

The Tabs API is available to extension service workers and extension pages, not content scripts. Put the capture call in the service worker (as below) or in a popup/options page. A content script can send a message, but it should not call chrome.tabs.captureVisibleTab() itself.

Create the Manifest V3 project

Make a directory such as visible-shot containing manifest.json, service-worker.js, and an icon if you plan to publish. This minimal manifest targets Chrome’s current Manifest V3 format.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
{
  "manifest_version": 3,
  "name": "Visible Tab Shot",
  "version": "1.0.0",
  "description": "Capture the visible area of the active tab.",
  "permissions": ["activeTab", "downloads"],
  "background": {
    "service_worker": "service-worker.js"
  },
  "action": {
    "default_title": "Capture visible tab"
  },
  "commands": {
    "capture-visible-tab": {
      "suggested_key": {
        "default": "Ctrl+Shift+Y",
        "mac": "Command+Shift+Y"
      },
      "description": "Capture the visible area of the active tab"
    }
  }
}

The downloads permission lets the extension save the image through Chrome’s downloads API. If you instead return the image to a popup for a user-initiated link click, you can design a different export path, but downloading from the worker keeps this example self-contained.

Capture the active tab and download a PNG

Add this service worker. It handles both the toolbar action and the optional keyboard command. The callback receives a data URL; passing format: "png" requests PNG output.

async function captureVisibleTab() {
  const [tab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true });

  if (!tab || tab.windowId === undefined) {
    throw new Error("No active tab is available");
  }

  const imageDataUrl = await chrome.tabs.captureVisibleTab(tab.windowId, {
    format: "png"
  });

  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
  await chrome.downloads.download({
    url: imageDataUrl,
    filename: `visible-shot-${stamp}.png`,
    saveAs: true
  });
}

chrome.action.onClicked.addListener(() => {
  captureVisibleTab().catch((error) => {
    console.error("Screenshot failed", error);
  });
});

chrome.commands.onCommand.addListener((command) => {
  if (command === "capture-visible-tab") {
    captureVisibleTab().catch((error) => {
      console.error("Screenshot failed", error);
    });
  }
});

The call is tied to the window containing the active tab. Querying lastFocusedWindow avoids accidentally capturing a tab in a background window. The filename is generated locally; no image data leaves the browser in this implementation.

Load and use the unpacked extension

  1. Open chrome://extensions in Chrome.
  2. Enable Developer mode.
  3. Choose Load unpacked and select the project directory.
  4. Pin “Visible Tab Shot” from the extensions menu, open an ordinary web page, and click the toolbar icon.
  5. Accept Chrome’s download prompt if saveAs is enabled. The resulting PNG contains only the viewport that was visible at capture time.

After editing manifest.json, reload the extension from the extensions page. Service-worker changes can be inspected with the worker’s Service worker link and its DevTools console.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the API captures—and what it cannot

Viewport only

captureVisibleTab() rasterizes what Chrome currently displays in the tab’s visible area. It does not automatically scroll, expand accordions, load lazy content below the fold, or include the browser’s tabs and address bar.

Full-page workflows

A full-page feature must determine document dimensions, scroll through positions, capture each viewport, and stitch overlapping images. Fixed headers, sticky elements, animations, responsive breakpoints, and lazy-loaded assets make stitching difficult. You also need safeguards for pages that change while scrolling. There is no universal one-call full-page result from this API.

Formats and quality

Chrome supports PNG and JPEG options for the capture call. PNG is lossless and suitable for text; JPEG is smaller but introduces compression artifacts. The returned image is a data URL, so very large captures consume memory while being passed between APIs. Keep the visible viewport and export path in mind when supporting high-device-scale-factor displays.

Rate and cost of capture

Chrome documents a ceiling of two capture calls per second and describes capture as expensive. Queue or debounce repeated requests, especially for keyboard shortcuts or automated scrolling. Show progress for multi-shot workflows and stop when a tab closes or navigation changes.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Privacy and Chrome Web Store requirements

Minimize collection

A screenshot can contain passwords, health information, customer records, private messages, or proprietary source code. This sample stores the image through Chrome’s download mechanism and sends nothing to a server. If your extension uploads images, disclose the destination, retention period, purpose, and deletion process before capture.

Website content and browsing activity are personal-data categories identified in Mozilla’s extension privacy guidance. Request only the permissions you need, avoid collecting URLs unless required, and provide a clear privacy policy when your data practices require one.

Make behavior obvious

Use an explicit user action, a descriptive toolbar title, and a visible success or failure message. Do not capture silently on every navigation. Explain whether screenshots are local files or transmitted to a service.

Keep executable logic in the package

Manifest V3 store review expects functionality to be discernible from the submitted code. Do not fetch JavaScript from a remote server and execute it at runtime. Remote configuration or data may be allowed in stated policy exceptions, but your capture logic, dependencies, and event handlers should be packaged and reviewable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common failures and fixes

Symptom Likely cause Fix
Cannot access contents of url or a rejected capture The tab is a restricted browser page, or temporary access was not granted by a user action. Test on a normal web page and invoke from the toolbar or command. Do not promise support for internal Chrome pages.
File URL does not capture File access is disabled for the extension. Open chrome://extensions, select the extension’s details, and enable Allow access to file URLs.
chrome.tabs is undefined in a content script Tabs APIs are not available in content scripts. Send a message to the service worker or move the call into an extension page.
Download fails or prompts repeatedly The downloads permission is missing, or saveAs is forcing a chooser. Declare downloads, verify the worker console, and set saveAs: false if your UX permits automatic saving.
Blank or incomplete image The page is still painting, a navigation occurred, or content is outside the viewport. Capture after the page settles, retry once, and explain that below-the-fold content needs a separate full-page implementation.
Too many requests are rejected You exceeded Chrome’s documented two-calls-per-second limit. Throttle to two or fewer calls per second and queue scrolling captures.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Testing checklist before distribution

  • Test toolbar and keyboard invocation on ordinary HTTP and HTTPS pages.
  • Check pages with long titles, sticky headers, animations, and high-density displays.
  • Verify behavior when the active tab closes or navigates during capture.
  • Test denied downloads, file URLs, and restricted Chrome pages without claiming unsupported coverage.
  • Confirm no screenshot, URL, or browsing history is sent anywhere unless your disclosure and implementation explicitly require it.
  • Review the manifest and bundled code for remote executable scripts before submitting to the Chrome Web Store.

Or skip the browser setup

If you need server-side screenshots rather than a user-visible browser button, ScreenshotNeo provides a single HTTP request for PNG, JPEG, WebP, or PDF output. For example:

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

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo documentation for parameters. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

When to choose each approach

Requirement Best fit
A user captures the current viewport locally Chrome extension with activeTab and captureVisibleTab()
Automated URLs, PDFs, cleanup, or backend workflows ScreenshotNeo API
AI agents need screenshot and page-information tools ScreenshotNeo MCP server
Whole-page capture inside the browser Custom scrolling and stitching, with careful throttling and page-change handling

Frequently Asked Questions

Can a Chrome extension capture a tab without showing a popup?

Yes. A toolbar action or command can invoke the service worker directly; the user still needs to perform that explicit action for an activeTab grant.

Does the screenshot include Chrome’s address bar?

No. The API captures the web page’s visible area, not browser UI.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can I publish an extension that uploads every screenshot?

Only with a clear, disclosed purpose and data-handling policy that matches the implementation and store requirements; automatic collection of page content deserves particular scrutiny.

Quick Recap

Bestseller No. 1

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.