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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

html2canvas cannot reliably capture a live Google Map or every Google chart because it reconstructs a page from readable DOM and CSS; it does not ask the browser for a pixel screenshot. Map tiles, overlays, frames and chart resources often come from another origin. Browser same-origin rules can make those pixels unavailable, while a chart may still be drawing or may use a canvas/SVG feature html2canvas does not reproduce. The result is a blank map, missing labels, an incomplete chart, or a SecurityError when you try to export the canvas.

The practical fix is to choose the capture method that matches the asset: enable CORS when you control the image server, use an authorized same-origin proxy when you do not, replace a live map with a Google Maps Static API image, export a Google Chart with its own PNG method, or use a real browser automation tool for a pixel-faithful page capture.

What html2canvas actually captures

It paints a new canvas from page data

html2canvas walks the target element, reads the DOM and supported CSS properties, and paints an approximation into a new <canvas>. It is useful for cards, invoices and other interfaces made from ordinary HTML, text and same-origin images. It is not the browser’s native screenshot pipeline, so it does not automatically include every pixel the user can see.

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.
  • Only DOM nodes and CSS features that the library understands are reconstructed.
  • Resources must be readable under browser origin rules, or they must be served with an appropriate CORS response or through a permitted proxy.
  • Cross-origin iframes cannot be inspected through contentDocument.
  • A canvas that already contains an unreadable cross-origin image becomes tainted; reading pixels or calling toDataURL() is then blocked.

Why the browser can display pixels that JavaScript cannot read

The browser may show an image or map tile to a visitor while withholding the underlying pixels from script running on your origin. This separation prevents a page from silently extracting data from another site. html2canvas follows that security boundary; it cannot turn a forbidden resource into a readable one.

Why a live Google Maps widget disappears

Maps is an application, not one image

A Google Maps JavaScript widget is assembled from many requests: tiled imagery, controls, markers, overlays and sometimes frames or other embedded resources. Those files are commonly served from Google-controlled origins rather than the origin of your page. html2canvas cannot read arbitrary cross-origin pixels, so it may skip tiles and leave an empty background, or produce a partial map with controls but no imagery.

What cross-origin failures look like

  • Blank map: the tile images were skipped because they did not provide an acceptable CORS response.
  • Partial map: same-origin labels or controls rendered, while external tiles or overlays did not.
  • SecurityError on export: an external image was drawn into a canvas, tainting it before toDataURL() or pixel reads.
  • Missing embedded content: a cross-origin iframe’s document cannot be read by html2canvas.

These are browser-enforced boundaries, not an option that can be switched off in html2canvas.

Why allowTaint is not a bypass

allowTaint: true allows rendering to continue even when a resource may taint the output. It does not grant permission to read the pixels. If the resulting canvas is tainted, toDataURL(), getImageData() and similar reads remain unsafe and fail. Use it only when you do not need pixel extraction and have accepted the consequences; it is not a security-policy workaround.

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

Why Google charts are blank or incomplete

The chart may use canvas, SVG or external resources

A chart can be drawn into its own canvas, represented as SVG, or depend on fonts and other external resources. html2canvas implements only the drawing and CSS features it supports. Unsupported SVG constructs, foreign resources, canvas content or tooltip layers can therefore disappear even when the surrounding HTML captures correctly.

Capture timing matters

Starting html2canvas immediately after chart.draw() can race the chart renderer. Labels, axes and data may not exist yet, producing a blank or half-rendered result. Wait for the chart library’s documented ready event, and wait for fonts and images used by the surrounding page before starting a capture.

Diagnose the symptom before changing options

  • If the chart is visibly unfinished in the browser, fix readiness first.
  • If only an external image or background is missing, investigate CORS rather than scale.
  • If the chart is visible but exporting throws a security exception, inspect whether its source canvas was tainted.
  • If labels vanish but bars or lines remain, an unsupported SVG/CSS feature is a more likely cause than origin policy.

Choose the right capture path

Approach Live interactive state Cross-origin requirement Keys or billing Runs where Typical result
ScreenshotNeo Captures the rendered page state Handled by the service’s browser capture Plans listed below; clean shots only are billed HTTP API or MCP server PNG, JPEG, WebP or PDF
html2canvas with CORS DOM reconstruction, not a browser screenshot Asset server must send Access-Control-Allow-Origin No map-specific key, but the asset provider may require one Browser Canvas export when every resource is readable
Same-origin proxy DOM reconstruction Your proxy fetches and serves authorized assets from your origin Operational and privacy responsibility is yours Browser plus your server More readable assets, subject to terms and implementation
Maps Static API image Fixed map image; no panning or tooltips Returned image is embedded as an ordinary <img> Authentication, billing, quotas and Maps Platform terms apply Browser or server GIF, PNG or JPEG map image
Google Chart native export Defined chart state Uses the chart’s own export path Depends on the chart service Browser PNG data URI for supported charts
Puppeteer or Playwright Closest to what a real browser displays Browser still follows normal network and permission rules Your browser infrastructure Server or CI Page or element screenshot and PDF

Fix html2canvas when you control the assets

Enable CORS on the image server

Set useCORS: true and configure every image or tile server you control to return an Access-Control-Allow-Origin value that permits the requesting origin. The option only asks html2canvas to make a CORS request; it cannot manufacture response headers.

async function captureReport() {
  await document.fonts.ready;
  const node = document.querySelector('#report');
  const canvas = await html2canvas(node, {
    useCORS: true,
    allowTaint: false,
    scale: Math.min(window.devicePixelRatio || 1, 2),
    backgroundColor: '#ffffff'
  });
  const link = document.createElement('a');
  link.download = 'report.png';
  link.href = canvas.toDataURL('image/png');
  link.click();
}

Use this for images whose server is configured for your origin. It will not make Google-owned map tiles readable merely because the option is present.

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

Use a same-origin proxy only with authorization

html2canvas has a proxy option for assets that your server is allowed to retrieve. The proxy must validate destinations, avoid forwarding private credentials, set an appropriate content type, and respect the asset provider’s terms and privacy requirements.

const canvas = await html2canvas(document.querySelector('#report'), {
  useCORS: true,
  proxy: '/asset-proxy',
  allowTaint: false
});

A proxy changes the trust boundary: your server becomes responsible for what it fetches and stores. Do not proxy arbitrary URLs or use this method to evade access controls.

Wait for the page before capturing

Wait for the map or chart container, fonts, images and any application-specific ready signal. A delay alone is less reliable than waiting for a selector or an explicit event, because network speed and rendering time vary.

Replace a live map with a Static API image

The Google Maps Static API returns a GIF, PNG or JPEG in response to an HTTP request. Build that request with the map’s center, zoom, size and any required markers or paths, then put the returned URL in a normal image element. html2canvas can usually copy that image when its response is readable to your page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function placeStaticMap(staticImageUrl) {
  const image = new Image();
  image.alt = 'Map showing the selected location';
  image.onload = () => {
    const container = document.querySelector('#map-print');
    container.replaceChildren(image);
  };
  image.onerror = () => {
    console.error('The Static API image could not be loaded');
  };
  image.src = staticImageUrl;
}

// Pass the URL returned by your authorized Maps Static API request.
placeStaticMap(staticImageUrl);

This solves the live-tile problem by reducing the map to one image, but it intentionally removes panning, zooming, tooltips and other interactivity. Authentication, billing, quotas and Google Maps Platform terms still apply to the API request.

Export Google Charts with the chart library

For supported Google Core Charts and GeoCharts, wait for the ready event and call getImageURI(). This is more faithful than asking html2canvas to reconstruct the chart’s internal drawing surface.

const chart = new google.visualization.LineChart(
  document.querySelector('#chart')
);

google.visualization.events.addListener(chart, 'ready', () => {
  const pngUri = chart.getImageURI();
  const image = document.querySelector('#chart-image');
  image.src = pngUri;
  image.alt = 'Exported line chart';
});

chart.draw(data, options);

Keep the export tied to the ready callback; calling it before the event can return an incomplete result. Native export represents the chart state, not the rest of your application’s surrounding UI. If your chart type does not support this method, choose an image-rendered chart implementation or capture the complete page in a real browser.

Use a real browser for a pixel-faithful capture

Puppeteer and Playwright drive an actual browser page, so they can capture the rendered result rather than rebuilding it from DOM and CSS. They are appropriate for server-side jobs, CI and pages that depend on browser layout, JavaScript and lazy loading. They still cannot defeat authentication, robots controls or cross-origin security; the browser must be able to load the page normally.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless: true});
  const page = await browser.newPage({
    viewport: { width: 1440, height: 1000, deviceScaleFactor: 1 }
  });
  await page.goto('https://example.com/dashboard', {
    waitUntil: 'networkidle2',
    timeout: 90000
  });
  await page.waitForSelector('#map, #chart', {timeout: 30000});
  await page.screenshot({path: 'dashboard.png', fullPage: true});
  await browser.close();
})();

Replace the example address and selector with your page. For deterministic output, set the viewport, wait for the application’s own map or chart-ready signal, and avoid capturing while animations are in progress.

Performance, canvas limits and reliability

  • Control dimensions: very large width, height or device-pixel scale can exceed browser canvas area limits and fail silently. Capture a smaller element, reduce scale, or split a long document into sections.
  • Load lazy content: scroll or trigger the page’s lazy-load mechanism before capture; otherwise below-the-fold tiles and images may not exist yet.
  • Use a deliberate scale: device-pixel-ratio improves sharpness but multiplies memory use. A capped value such as 1 or 2 is safer for long pages.
  • Wait for fonts and images: call document.fonts.ready, wait for image completion, and use the chart’s ready event rather than an arbitrary short timeout.
  • Separate data from pixels: keep the underlying map coordinates and chart data accessible as text or structured data; a PNG is not selectable or inherently accessible.
  • Test failure paths: handle timeouts, blocked resources, blank pages and export exceptions instead of returning a misleading image.

Troubleshooting common failures

Symptom Likely cause Fix
Google Map is completely blank Cross-origin tiles were skipped Use a Static API image, an authorized proxy, or a real browser capture; useCORS alone cannot add headers.
Only some map layers appear Different layers have different origins or CORS responses Make every required asset readable, or replace the widget with one static image.
SecurityError: Tainted canvases may not be exported An unreadable image or canvas was drawn before export Remove the offending asset, obtain a valid CORS response, or use a permitted proxy; do not rely on allowTaint.
Chart image is blank Capture began before rendering completed Call getImageURI() after ready, or wait for an application-specific readiness promise.
Chart bars render but labels or tooltips do not Unsupported SVG/CSS or overlay content Use the chart’s native PNG export or a browser screenshot.
Output is clipped or transparent Canvas dimensions, background or scale are unsuitable Set an explicit background, lower scale, reduce dimensions and capture in sections.
Server-side script says document is not defined html2canvas expects browser globals Run it in a browser, or use Puppeteer/Playwright for Node.js rendering.
Proxy capture exposes private data Proxy accepts arbitrary destinations or forwards secrets Allow-list hosts, strip credentials, limit response size and operate only with authorization.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo is the first service to try when you need an API screenshot rather than a hand-built browser pipeline: it removes consent banners, newsletter popups and chat widgets before capture, bills only clean shots, and its paid entry plan is $5 for 3,000 shots.

One GET request returns PNG, JPEG, WebP or PDF. The API can wait for a selector, delay or network idle; load lazy images; capture a CSS-selected element; set a device preset or viewport, dark mode, retina scale, timezone and geolocation; apply custom CSS or JavaScript; click an element; hide selectors; block ads, trackers, requests or resource types; supply headers, cookies, user-agent and Authorization; resize images; cache with a chosen TTL; create signed links; submit asynchronous jobs with signed webhooks; capture up to 100 URLs per bulk call; and expose usage and OpenAPI endpoints. Its MCP server supplies take_screenshot, get_page_info and capture_pdf tools to Claude, Cursor and other MCP clients.

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 API documentation for parameter details. The response includes X-Page-Verdict and X-Billed headers, so bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing.

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

Python

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)

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}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);

The Free plan includes 1,000 shots per month with no card. Paid plans are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000 and Business $249 for 1,000,000; yearly billing gives two months free, and every feature is on every plan. Create a free ScreenshotNeo account to start without a card.

FAQ

Can html2canvas capture a map after I hide the controls?

Hiding controls changes the DOM but does not change the origin of the map tiles. The imagery can still be skipped or taint the canvas, so use a readable static image or a browser capture for the map itself.

Does a PNG export preserve chart accessibility?

No. A PNG is a visual snapshot. Keep the chart’s data, labels and an accessible text representation in the page even when you provide an image download.

Will a browser automation screenshot bypass a CAPTCHA?

No. Puppeteer, Playwright and ScreenshotNeo can report a blocked or failed page, but they should not be treated as a way to defeat bot checks or access controls.

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

Frequently Asked Questions

Can html2canvas capture a map after I hide the controls?

Hiding controls does not change the origin of map tiles. Use a readable static image or a browser capture for the imagery.

Does a PNG export preserve chart accessibility?

No. Keep the chart data and an accessible text representation alongside any PNG.

Will browser automation bypass a CAPTCHA?

No. A CAPTCHA or blocked page remains a failed or restricted capture.

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.

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