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

Render an HTML/CSS logo in the browser with html2canvas: select the logo element, await a canvas, export it with toDataURL('image/png'), and download the result. Use backgroundColor: null for transparency, scale: window.devicePixelRatio for sharper pixels, and configure CORS for every remote image or font.

What the browser actually does

HTML and CSS are not image files. A browser paints the logo from DOM nodes, styles, fonts, gradients, pseudo-elements and assets. To create a PNG, JavaScript must rasterize that visual representation into pixels. The practical browser workflow is:

  1. Find the logo element.
  2. Ask html2canvas to reconstruct that element in a canvas.
  3. Convert the canvas to a PNG data URL.
  4. Assign the URL to a download link and click it.

html2canvas is available through npm, yarn, pnpm, or a browser CDN and returns a Promise, so the capture code must be asynchronous.

Install and prepare the logo

Install with a package manager

npm install html2canvas

Then import it in an application bundled for the browser:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import html2canvas from 'html2canvas';

For a page using a CDN, load the browser build before your own script. Keep the logo in a dedicated element with a stable size; this makes output dimensions predictable.

<div id="logo" class="logo">
  <span class="mark">N</span>
  <span class="word">Neo Labs</span>
</div>

Complete HTML/CSS-to-PNG example

The following example preserves transparency, uses the device pixel ratio for density, enables CORS-aware image loading, and downloads the finished file.

import html2canvas from 'html2canvas';

async function downloadLogo() {
  const logo = document.querySelector('#logo');
  if (!logo) throw new Error('Logo element was not found');

  const canvas = await html2canvas(logo, {
    backgroundColor: null,
    scale: window.devicePixelRatio,
    useCORS: true
  });

  const link = document.createElement('a');
  link.download = 'logo.png';
  link.href = canvas.toDataURL('image/png');
  link.click();
}

document.querySelector('#download-logo').addEventListener('click', downloadLogo);

In markup, provide a button such as <button id="download-logo">Download PNG</button>. Calling toDataURL() without a supported MIME argument also produces PNG; specifying 'image/png' makes the intent explicit.

Control transparency, size and sharpness

Transparent background

Set backgroundColor: null when the logo should have no rectangle behind it. A CSS background on the logo itself still renders; this option controls the canvas backdrop.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

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

Retina and print density

scale multiplies the raster dimensions. window.devicePixelRatio usually gives crisp output on high-density displays. For a 300 CSS-pixel-wide logo on a 2× display, the canvas will generally be about 600 pixels wide. Very large scales consume more memory, so choose a fixed value when you need identical output across machines.

Capture a controlled region

Use width, height, x, and y to define a precise capture rectangle. windowWidth and windowHeight control the virtual viewport used while rendering. These settings are useful when a logo has overflowing content or when the result must match a known export size rather than the element’s current layout.

const canvas = await html2canvas(logo, {
  backgroundColor: null,
  scale: 2,
  width: 640,
  height: 180,
  windowWidth: 1280,
  windowHeight: 720,
  useCORS: true
});

Inspect canvas.width and canvas.height if an integration requires exact pixel dimensions.

Make images, fonts and backgrounds appear

Wait for assets before capture

Capture only after the logo’s images and fonts have loaded. Otherwise the canvas can contain an empty image box, fallback text, or a different layout.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await document.fonts.ready;
await Promise.all(
  [...document.images].filter(img => !img.complete)
    .map(img => new Promise(resolve => {
      img.addEventListener('load', resolve, { once: true });
      img.addEventListener('error', resolve, { once: true });
    }))
);

If you control the markup, wait for only the assets used by the logo rather than every image on the page.

Understand the CORS requirement

A cross-origin image can taint the canvas. Once tainted, browser security prevents toDataURL(), toBlob(), and pixel-reading APIs and raises a SecurityError. useCORS: true asks the browser to make a CORS request, but the image server must also send an appropriate Access-Control-Allow-Origin response header. If the server cannot do that, serve the asset from your own origin or fetch it through a same-origin proxy. JavaScript cannot bypass this rule.

const canvas = await html2canvas(logo, {
  useCORS: true,
  backgroundColor: null
});
const png = canvas.toDataURL('image/png');

The same rule applies to CSS background-image, web fonts and resources referenced by an SVG. Inline small assets when practical, or configure their servers before exporting.

What html2canvas can and cannot reproduce

html2canvas reconstructs a representation from the DOM; it does not take a pixel-for-pixel screenshot of the compositor. Only CSS properties implemented by the library render reliably. Complex filters, masks, unsupported blend modes and unavailable fonts can differ from what the user sees. Cross-origin iframes cannot be rendered. The foreignObjectRendering option may improve coverage in browsers that support it, but it is not a guarantee of complete CSS support.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const canvas = await html2canvas(logo, {
  foreignObjectRendering: true,
  backgroundColor: null,
  useCORS: true
});

For a brand mark that depends on advanced effects, compare the exported PNG with the on-screen logo at the exact target size. If fidelity is mandatory, simplify the CSS for the export version or use a source format designed for graphics.

Direct conversion when the logo is already SVG

If the logo is an inline SVG rather than arbitrary HTML/CSS, serializing the SVG and drawing it to an off-screen canvas is often simpler. This avoids DOM reconstruction, while external fonts and images inside the SVG still need correct loading and CORS.

async function svgToPng(svg, width, height) {
  const source = new XMLSerializer().serializeToString(svg);
  const blob = new Blob([source], { type: 'image/svg+xml;charset=utf-8' });
  const url = URL.createObjectURL(blob);

  try {
    const image = new Image();
    image.src = url;
    await image.decode();

    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const context = canvas.getContext('2d');
    context.clearRect(0, 0, width, height);
    context.drawImage(image, 0, 0, width, height);
    return canvas.toDataURL('image/png');
  } finally {
    URL.revokeObjectURL(url);
  }
}

const pngUrl = await svgToPng(document.querySelector('svg'), 800, 240);
const link = document.createElement('a');
link.download = 'logo.png';
link.href = pngUrl;
link.click();

Troubleshooting blank or incorrect exports

Symptom Likely cause Fix
SecurityError when exporting A cross-origin image, font or SVG resource tainted the canvas. Enable useCORS, configure Access-Control-Allow-Origin, or proxy/inline the asset.
Logo is blank The selector matched nothing, the element is hidden, or rendering ran before layout/assets were ready. Check the element, make it renderable, await document.fonts.ready and image loading, then capture.
Images are missing The image server rejected the CORS request or the image had not loaded. Inspect the network response headers and wait for the image; fix the server or use same-origin delivery.
Text looks different The intended web font was unavailable during reconstruction. Wait for fonts, verify the font response, and provide a fallback that preserves the logo’s dimensions.
Effects or masks differ The CSS feature is not implemented by html2canvas. Use simpler export CSS, test foreignObjectRendering where supported, or export from an SVG/source design.
Output is blurry The canvas was rendered at CSS resolution or enlarged after export. Increase scale before capture and avoid enlarging the PNG afterward.
Browser becomes slow or crashes A very large element or scale requires excessive canvas memory. Capture only the logo, reduce scale, constrain dimensions, and release generated URLs when finished.

Performance, reliability and security considerations

  • Capture the smallest element. Rendering an entire page costs more than rendering the logo node.
  • Use deterministic layout. Fix the logo’s width, height, fonts and viewport when exports must match across browsers.
  • Handle rejection. Wrap the awaited call in try/catch and show a useful error instead of silently creating a broken download.
  • Prefer toBlob() for large files. A Blob avoids keeping a long base64 string in memory; create an object URL, download it, then call URL.revokeObjectURL().
  • Protect sensitive content. The resulting PNG contains whatever the selected element displays. Do not export secrets into a file that users can download.
try {
  const canvas = await html2canvas(document.querySelector('#logo'), {
    backgroundColor: null,
    scale: 2,
    useCORS: true
  });

  const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
  if (!blob) throw new Error('PNG encoding failed');

  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.download = 'logo.png';
  link.href = url;
  link.click();
  URL.revokeObjectURL(url);
} catch (error) {
  console.error('Logo export failed', error);
}

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server when you want a rendered URL rather than client-side canvas code. It accepts cookie or 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, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients.

Use the ScreenshotNeo API documentation for the full option set, including full-page and selector captures, device presets, retina scale, custom CSS/JavaScript, waits, request blocking, headers, cookies, authorization, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous webhooks, bulk capture and usage data.

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

cURL

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}`);

The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan, and yearly billing gives two months free. Create a free ScreenshotNeo account to try it.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

FAQ

Can I export JPEG instead of PNG?

Yes. Pass a supported MIME type such as image/jpeg to toDataURL() or toBlob(); PNG remains the appropriate choice for transparent logos.

Why does a hidden logo export incorrectly?

A display:none element has no layout to reconstruct. Render it in the document, capture it, and hide it after the Promise resolves, or maintain an off-screen export copy with explicit dimensions.

Does html2canvas capture an iframe logo?

It cannot render a cross-origin iframe. Move the logo into the parent document, obtain a same-origin arrangement, or capture the iframe’s source separately.

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

Should I use html2canvas for a production brand asset?

Use it when the source is genuinely HTML/CSS and browser-side export is convenient. For a simple inline SVG, direct SVG conversion usually has less reconstruction overhead and a clearer path to consistent geometry.

Frequently Asked Questions

Can I export JPEG instead of PNG?

Yes. Pass a supported MIME type such as image/jpeg to toDataURL() or toBlob(); PNG remains the appropriate choice for transparent logos.

Why does a hidden logo export incorrectly?

A display:none element has no layout to reconstruct. Render it in the document, capture it, and hide it after the Promise resolves, or maintain an off-screen export copy with explicit dimensions.

Does html2canvas capture an iframe logo?

It cannot render a cross-origin iframe. Move the logo into the parent document, obtain a same-origin arrangement, or capture the iframe’s source separately.

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

Should I use html2canvas for a production brand asset?

Use it when the source is genuinely HTML/CSS and browser-side export is convenient. For a simple inline SVG, direct SVG conversion usually has less reconstruction overhead and a clearer path to consistent geometry.

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.