Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteIn a Chrome extension, call chrome.tabs.captureVisibleTab() after a user action, convert its returned data URL to a Blob, and upload it with fetch() from the extension’s service worker or an extension page. Declare the capture permission and permission for the API host in the manifest. The upload method, authentication, multipart field, accepted formats, size limit, and response parsing are determined by the receiving API—not by Chrome.
What the extension captures—and what the API receives
chrome.tabs.captureVisibleTab() captures the active tab’s visible viewport and returns a data URL. It does not produce a full-page image. Chrome documents a maximum of two calls per second for this method. See the Chrome tabs API reference.
As an Amazon Associate I earn from qualifying purchases.
The screenshot API is a separate part of the workflow. Before implementing the request, check its documentation for the exact endpoint, HTTP method, authorization scheme, accepted image formats, request body or multipart field name, payload limit, and response format. The example below uses multipart form data and a bearer token as a template; those details are not universal.
Declare the permissions in Manifest V3
For a capture initiated by the user, activeTab is usually narrower than granting access to every site. Add a host permission for the API origin so extension-owned code can make the cross-origin request. Replace api.example.com with the API host, narrowing the pattern as appropriate.
#1 Best Overall
{
"manifest_version": 3,
"permissions": ["activeTab"],
"host_permissions": ["https://api.example.com/*"],
"background": {
"service_worker": "service-worker.js"
}
}
Chrome documents activeTab and <all_urls> as permission options for visible-tab capture. Use the broader permission only when the extension’s behavior requires it. Chrome also supports optional host permissions that can be requested at runtime; see Declare permissions.
Capture the visible tab and upload it
Put the capture and upload in extension-owned code, such as the service worker, then invoke it in response to an explicit extension UI action. This example expects a multipart field named screenshot, bearer-token authentication, and a JSON response. Change those parts to match the receiving service.
async function captureAndUpload(apiUrl, token) {
const dataUrl = await chrome.tabs.captureVisibleTab({
format: "png"
});
const imageBlob = await (await fetch(dataUrl)).blob();
const form = new FormData();
form.append("screenshot", imageBlob, "screenshot.png");
const response = await fetch(apiUrl, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`
},
body: form
});
if (!response.ok) {
throw new Error(`Screenshot upload failed: HTTP ${response.status}`);
}
return response.json();
}
When sending FormData, do not set the Content-Type header yourself. The browser must add the multipart boundary. If the API requires raw binary or JSON/base64 instead, follow its specification rather than sending this multipart body.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Check the response format before calling response.json(). If the endpoint returns an empty body, text, or binary data, parse it accordingly. An HTTP success status does not guarantee that the response is JSON.
Rank #3
Choose the right execution context and protect the request
Cross-origin extension requests need permission for the destination host. Make the request from the service worker or an extension page; a content script remains subject to the page’s same-origin restrictions. Chrome’s guidance is in Cross-origin network requests.
- Use a fixed, trusted API URL in extension code. Do not let a webpage supply an arbitrary URL for the extension to fetch.
- If a content script sends a message to the service worker, validate the sender and expose only a constrained capture-and-upload operation.
- Use HTTPS. Avoid logging screenshot bytes, authorization tokens, or sensitive response contents.
- Tell users when a screenshot is captured and uploaded; the visible tab may contain personal or confidential information.
- Keep the operation tied to a user action and transmit only the image and metadata needed for its stated purpose.
Manifest V3 service workers are event-driven and may become dormant; they also have no DOM access. Handle capture and upload as part of the extension event, and return success or failure to the UI rather than depending on an open page or in-memory state to persist. See About extension service workers.
When visible-tab capture is not enough
The method captures only what is visible in the active tab at the time of the call. Content below the fold is not included. A full-page result needs a different design, such as scrolling and stitching captures, or another capture mechanism; validate that approach for the browser and pages involved. The Chrome capture call’s documented rate limit is two calls per second, so avoid rapid capture loops.
Recommended Free Tools
Troubleshoot common failures
- Capture permission error: Confirm the extension has
activeTabor<all_urls>, and that the call targets the active tab in the intended window. - Cross-origin fetch fails: Check that
host_permissionscovers the API host and that the request runs in extension-owned code, not a content script. - API rejects the upload: Verify the endpoint, method, multipart field name, authorization format, allowed image format, payload limit, and response requirements against that API’s documentation.
- Multipart parsing fails: If using
FormData, remove any manually setContent-Typeheader so the browser can supply the boundary. - JSON parsing throws after a successful response: Confirm the service actually returns JSON; parse the response as text or another format if its contract specifies that.
- Calls are throttled: Keep
captureVisibleTab()at or below Chrome’s documented two calls per second. - The image cuts off the page: This is expected for visible-tab capture; it does not include content below the viewport.
Or skip the browser setup
If your goal is to capture a website from code rather than capture the user’s current browser tab, ScreenshotNeo provides a screenshot API and MCP server. Its one-call API example is:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for request details. It removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000. Sign up for ScreenshotNeo’s free plan.
Frequently Asked Questions
Does captureVisibleTab() take a full-page screenshot?
No. It captures the active tab’s visible area; content below the viewport is excluded.
Can a content script upload the screenshot directly to another domain?
Extension host permissions do not remove a content script’s page-origin restrictions. Make the cross-origin request from the service worker or an extension page.
Quick Recap
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.




