BlogScreenshots on your device
How to Let Intranet Users Capture the Current Page in a Browser
Build a one-click intranet page capture with a browser extension, or use getDisplayMedia when users must choose a screen or tab.
Use a browser extension with the activeTab permission when an intranet user should click once to capture the visible current tab. The extension calls chrome.tabs.captureVisibleTab() in Chromium browsers or browser.tabs.captureVisibleTab() in Firefox-based browsers, receives a data URL, and downloads it. This captures the visible viewport; the documented API does not promise a full-page image. Chrome’s tabs API documentation and Mozilla’s WebExtensions documentation describe this permission and return value.
Choose the right browser workflow
| Approach | Use it when | User experience | Important limits |
|---|---|---|---|
| Extension with active-tab capture | A toolbar button, context-menu item, or keyboard command should capture the current tab | User invokes the extension; it captures the active tab and downloads an image | Requires extension deployment and permissions; the documented call captures the visible area |
getDisplayMedia() |
The user must choose a tab, window, or screen for sharing or recording | The browser opens a picker and asks for permission | Requires HTTPS, user activation, and a fresh selection flow; it is not a silent persistent permission |
A normal intranet page cannot silently read and save the browser’s current tab. getDisplayMedia() is designed for user-selected display capture, while an extension has the browser permission model needed for an explicit “capture this page” action. See the MDN getDisplayMedia() reference and the Screen Capture API overview.
Build a one-click extension
1. Create the extension files
This minimal Manifest V3 extension adds a toolbar button. It requests activeTab, which Chrome describes as temporary access granted after a user invocation. The API also accepts the broader all_urls permission, but use the narrowest scope that meets your deployment requirements.
current-page-capture/
├── manifest.json
└── service-worker.js
2. Add the manifest
{
"manifest_version": 3,
"name": "Capture Current Intranet Page",
"version": "1.0.0",
"description": "Save the visible area of the active tab as a PNG.",
"permissions": ["activeTab", "downloads"],
"background": {
"service_worker": "service-worker.js"
},
"action": {
"default_title": "Capture current page"
}
}
3. Capture the active tab and download the image
chrome.action.onClicked.addListener(async (tab) => {
if (!tab.id || !tab.windowId) return;
try {
const dataUrl = await chrome.tabs.captureVisibleTab(tab.windowId, {
format: "png"
});
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
await chrome.downloads.download({
url: dataUrl,
filename: `intranet-page-${timestamp}.png`,
saveAs: true
});
} catch (error) {
console.error("Could not capture the active tab", error);
}
});
Firefox uses the WebExtensions namespace. If you maintain one codebase, call browser.tabs.captureVisibleTab() where the browser exposes the browser API, or use a compatibility wrapper such as globalThis.browser ?? chrome and test the supported browser versions.
4. Load and deploy it
- Open the browser’s extension management page.
- Enable developer mode for local testing.
- Choose “Load unpacked” and select the
current-page-capturedirectory. - Pin the extension, open an intranet page, and click the toolbar button.
- For a managed fleet, package and distribute the extension through your organization’s browser management system, then test updates and policy restrictions in a pilot group.
Permission and intranet design
activeTab versus all_urls
activeTab: Chrome grants temporary access after the user invokes the extension. It limits standing access and fits a manual capture button.all_urls: Gives broader host access. Use it only when your product needs to capture without a direct invocation or across hosts that the narrower model cannot cover.
The capture call requires activeTab or all_urls according to the API documentation. Explain the permission in your internal deployment notice so users understand why the extension can capture the page they explicitly choose.
Visible viewport versus full page
captureVisibleTab() captures what is visible in the tab. If users need content below the fold, provide an application-level export, print view, or a separate full-page capture workflow. Do not describe this API alone as a full-page screenshot solution.
Protected and restricted pages
Some browser-internal pages, extension pages, permission prompts, and organization-controlled surfaces may reject capture. Treat a failed call as a normal error path: show a short message, log the browser error for administrators, and let the user retry on the intranet page itself.
Alternative: let the user choose a surface with getDisplayMedia()
Use this API when the user must select a tab, window, or screen, such as a support session or recording tool. It requires a secure context, a user interaction, and a browser picker. Permission cannot be silently retained for automatic reuse.
<button id="capture">Choose a tab or screen</button>
<script>
const button = document.querySelector("#capture");
button.addEventListener("click", async () => {
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: { displaySurface: "browser" },
audio: false
});
const video = document.createElement("video");
video.srcObject = stream;
await video.play();
await new Promise((resolve) => {
if (video.readyState >= 2) resolve();
else video.addEventListener("loadeddata", resolve, { once: true });
});
const canvas = document.createElement("canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext("2d").drawImage(video, 0, 0);
const link = document.createElement("a");
link.download = "selected-surface.png";
link.href = canvas.toDataURL("image/png");
link.click();
stream.getTracks().forEach((track) => track.stop());
} catch (error) {
console.error("Display capture was cancelled or failed", error);
}
});
</script>
When this code runs inside an iframe, check the response’s Permissions Policy for display-capture. A policy allowance does not remove the browser’s user prompt. In managed Microsoft Edge deployments, administrators should also inspect the ScreenCaptureAllowed policy and its origin-specific exceptions.
Production checklist
- Define whether “page” means the visible viewport or a complete document.
- Require an explicit click or keyboard invocation for extension capture.
- Request
activeTabunless your tested workflow truly needs broader host access. - Use HTTPS for any page that calls
getDisplayMedia(). - Handle cancellation, denied permission, unsupported pages, and browser policy failures.
- Choose a predictable filename and let users select the destination when appropriate.
- Test the real intranet authentication flow, embedded frames, browser versions, and managed policies.
- Do not send captured images to a server unless your data-handling policy allows it.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
captureVisibleTab rejects the call |
The extension lacks activeTab or all_urls, or the page is restricted |
Check the manifest, invoke the extension from the target tab, and test on a regular intranet page. |
| The downloaded image shows only part of the document | The API captures the visible viewport | Scroll and capture multiple regions, add an application export, or use a purpose-built full-page capture service. |
| The display picker never appears | The call was not started by a user gesture, the page is not secure, or policy blocks display capture | Start it directly from a click, serve the page over HTTPS, and inspect iframe Permissions Policy and Edge policy settings. |
User cancels getDisplayMedia() |
Cancellation is part of the normal permission flow | Catch the exception and show a retry action without treating it as a server failure. |
| Capture works locally but not for employees | Managed browser policy, extension deployment, or version differences | Verify the installed extension version, enterprise policies, supported browser versions, and the actual intranet origin. |
| Images are too large | High viewport dimensions or display scale | Use PNG only when lossless output is needed; otherwise provide JPEG or WebP conversion after capture and define a retention policy. |
Performance, reliability, and privacy
Capturing the visible tab avoids a server round trip and normally finishes after the browser has rendered the current viewport. The main variables are page rendering time, image encoding, display scale, and download handling. Keep the extension event short, avoid repeated automatic captures, and provide feedback when a capture is being prepared.
For reliability, treat browser APIs and organization policy as separate failure domains. Record a local diagnostic message, include the browser error text in administrator logs, and never assume that a permission granted on one origin applies to every intranet host. For sensitive intranet content, keep image processing local unless a documented business requirement permits upload.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. If the target URL is reachable by the service, one GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for the complete option list.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://intranet.example.local/current -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://intranet.example.local/current"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://intranet.example.local/current'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', image);
ScreenshotNeo can accept cookie and consent banners before capture and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for 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.
Create a free ScreenshotNeo account to try 1,000 screenshots per month with no card.
FAQ
Can a regular intranet page capture the tab without an extension?
No. A page can request user-selected display capture with getDisplayMedia(), but the browser requires a picker and permission. It cannot silently reuse a permanent tab-capture grant.
Does activeTab grant access forever?
No. Chrome documents it as temporary access following a user invocation. Design the extension around an explicit action.
Can this capture a browser tab behind another window?
The documented API captures the visible active tab. Test the exact browser behavior your organization supports; do not assume it is a background-tab or full-document capture API.
Should I use getDisplayMedia() for a screenshot button?
Use it when user selection is part of the requirement. For a known current tab and a one-click action, an extension is the closer fit.


