HEIC on the Web: Browser Support and Best Practices
A developer's guide to handling HEIC files in web applications — browser support status, server-side conversion, client-side processing, and content negotiation strategies.
Web browsers do not broadly support HEIC. Only Safari decodes HEIC natively. Chrome, Firefox, Edge, and Opera cannot display HEIC images without JavaScript polyfills. This creates a clear engineering requirement: accept HEIC in upload flows, but never serve HEIC to browsers.
This guide covers the full developer workflow -- detecting HEIC uploads, converting server-side and client-side, choosing delivery formats, and implementing content negotiation. For background on the format itself, see What is HEIC?.
Browser Support for HEIC
HEIC browser support is limited to Safari. No other major browser has committed to native HEIC decoding. HEVC patent licensing costs are the primary barrier.
| Browser | HEIC Support | Notes | | --- | --- | --- | | Safari | Yes (macOS 11+, iOS 11+) | Native HEVC decoder in Apple hardware | | Chrome | No | No plans for native support | | Firefox | No | Blocked by HEVC licensing costs | | Edge | No | Relies on OS codec; inconsistent results | | Opera | No | Same Chromium limitation as Chrome | | Samsung Internet | No | No native HEIC decoding |
Safari's support comes from Apple's hardware HEVC decoders, present in every Apple device since 2017. Other browser vendors refuse to pay HEVC patent royalties. This situation is unlikely to change.
For comparison, WebP has 97%+ browser support and AVIF has 93%+ support. Both are royalty-free.
HEIC MIME Types and File Extensions
Correct MIME type handling is essential for detecting HEIC uploads. The IANA-registered types are:
| MIME Type | Description |
| --- | --- |
| image/heic | Single HEIC image (HEVC codec) |
| image/heic-sequence | HEIC image sequence (animation/burst) |
| image/heif | Single HEIF image (generic, any codec) |
| image/heif-sequence | HEIF image sequence |
Common file extensions are .heic and .heif. Apple's Live Photos use .heic for the still frame. Some cameras produce .heics for sequences.
Browsers may not populate the MIME type correctly. On some platforms, File.type returns an empty string for HEIC uploads. Always validate by file extension as a fallback.
Detecting HEIC Uploads
Reliable HEIC detection requires checking both the MIME type and the file extension. File signature (magic bytes) inspection adds a third layer of certainty.
function isHeicFile(file) {
// Check MIME type
const heicMimeTypes = [
'image/heic',
'image/heif',
'image/heic-sequence',
'image/heif-sequence',
];
if (heicMimeTypes.includes(file.type.toLowerCase())) {
return true;
}
// Fallback: check file extension
const extension = file.name.split('.').pop()?.toLowerCase();
return ['heic', 'heif', 'heics'].includes(extension);
}
For file input elements, set the accept attribute to include HEIC types:
<input
type="file"
accept="image/heic,image/heif,.heic,.heif,image/jpeg,image/png,image/webp"
/>
Including both MIME types and extensions in the accept attribute ensures compatibility across browsers and operating systems.
Server-Side Conversion
Server-side conversion is the most reliable approach for web applications that process user uploads. Three mature options exist.
Sharp (Node.js)
Sharp is the fastest Node.js image processing library. It uses libvips under the hood, which links to libheif for HEIC decoding.
import sharp from 'sharp';
async function convertHeicToWebP(inputBuffer) {
return sharp(inputBuffer)
.webp({ quality: 80 })
.toBuffer();
}
async function convertHeicToJpg(inputBuffer) {
return sharp(inputBuffer)
.jpeg({ quality: 85, mozjpeg: true })
.toBuffer();
}
Sharp handles HEIC input automatically when libheif is available. Install Sharp v0.33+ for full HEIC support. Processing a 12 MP HEIC image takes approximately 200-500ms on modern server hardware.
ImageMagick
ImageMagick supports HEIC through its libheif delegate. It is available on most Linux distributions and works well in Docker containers.
# Convert single file
magick input.heic -quality 85 output.webp
# Batch convert with resize
magick mogrify -format webp -quality 80 -resize 2048x2048\> *.heic
ImageMagick is slower than Sharp for programmatic use but excels at batch processing and CLI workflows.
libheif (C/C++)
libheif is the reference HEIF/HEIC decoder. Both Sharp and ImageMagick use it internally. Direct libheif integration gives maximum control over decoding parameters. Use libheif directly when building custom image pipelines in C, C++, Go, or Rust.
Client-Side Conversion
Client-side HEIC conversion eliminates server processing costs and avoids uploading potentially sensitive photos. Two JavaScript libraries handle HEIC decoding in the browser.
libheif-js
libheif-js compiles the C-based libheif library to WebAssembly. It provides low-level access to HEIC decoding, including multi-image containers and metadata extraction.
import libheif from 'libheif-js';
async function decodeHeic(buffer) {
const decoder = new libheif.HeifDecoder();
const images = decoder.decode(new Uint8Array(buffer));
const image = images[0];
const width = image.get_width();
const height = image.get_height();
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(width, height);
await new Promise((resolve) => {
image.display(imageData, (result) => resolve(result));
});
ctx.putImageData(imageData, 0, 0);
return canvas;
}
heic2any
heic2any provides a simpler API that converts HEIC files directly to Blob objects in JPG, PNG, or GIF format.
import heic2any from 'heic2any';
async function convertHeicToJpg(heicBlob) {
const jpgBlob = await heic2any({
blob: heicBlob,
toType: 'image/jpeg',
quality: 0.85,
});
return jpgBlob;
}
heic2any uses libheif-js internally. It trades configurability for convenience.
Web Workers for Non-Blocking Conversion
HEIC decoding is CPU-intensive and will block the main thread. A 12 MP HEIC image takes 1-3 seconds to decode via WebAssembly. Use Web Workers to keep the UI responsive.
// converter.worker.js
import heic2any from 'heic2any';
self.onmessage = async (event) => {
const { file, quality } = event.data;
try {
const result = await heic2any({
blob: file,
toType: 'image/jpeg',
quality: quality || 0.85,
});
self.postMessage({ success: true, blob: result });
} catch (error) {
self.postMessage({ success: false, error: error.message });
}
};
HEICify uses this exact pattern -- libheif-js running inside Web Workers -- to convert HEIC files entirely in the browser with no server uploads. Processing multiple files in parallel across multiple workers dramatically improves batch conversion throughput.
Image Delivery: Never Serve HEIC
Do not serve HEIC images to web browsers. With less than 20% browser support, HEIC will fail for the vast majority of users. Use a multi-format delivery strategy instead.
Recommended delivery formats
| Format | Browser Support | Best For | | --- | --- | --- | | WebP | 97%+ | Primary modern format for all images | | AVIF | 93%+ | Maximum compression, HDR content | | JPG | 100% | Universal fallback for photographs | | PNG | 100% | Fallback for images with transparency |
The picture element
The HTML <picture> element lets browsers select the optimal format from a list. Browsers pick the first source they support.
<picture>
<source srcset="/images/photo.avif" type="image/avif" />
<source srcset="/images/photo.webp" type="image/webp" />
<img src="/images/photo.jpg" alt="Description" width="800" height="600" />
</picture>
This serves AVIF to Chrome 85+, Firefox 93+, and Safari 16.4+. Browsers without AVIF support get WebP. Browsers without WebP support (a negligible percentage in 2026) get JPG.
Content negotiation with Accept headers
Server-side content negotiation uses the Accept request header to detect format support. Browsers declare supported image formats in this header.
Accept: image/avif,image/webp,image/apng,image/*,*/*;q=0.8
A Node.js middleware example:
function negotiateImageFormat(req) {
const accept = req.headers.accept || '';
if (accept.includes('image/avif')) return 'avif';
if (accept.includes('image/webp')) return 'webp';
return 'jpg';
}
CDNs like Cloudflare, Fastly, and AWS CloudFront can automate this negotiation. Configure them to vary responses by the Accept header and serve pre-generated format variants.
Include Vary: Accept in the response headers when serving different formats from the same URL. This prevents caches from serving the wrong format to the wrong browser.
Vary: Accept
Content-Type: image/webp
Performance Considerations
Server-side conversion benchmarks
Processing a 12 MP HEIC file (4032 x 3024 pixels):
| Tool | Decode Time | Output to WebP | Output to JPG | | --- | --- | --- | --- | | Sharp | ~200 ms | ~350 ms total | ~300 ms total | | ImageMagick | ~400 ms | ~700 ms total | ~600 ms total | | libheif CLI | ~150 ms | N/A (decode only) | N/A (decode only) |
Client-side conversion benchmarks
WebAssembly HEIC decoding in the browser (12 MP file, modern desktop CPU):
| Library | Decode Time | Full Conversion | | --- | --- | --- | | libheif-js | ~1.5 s | ~2.0 s (to canvas) | | heic2any | ~1.8 s | ~2.5 s (to JPG blob) |
Client-side decoding is 5-10x slower than native server-side decoding. This is acceptable for single-file conversions. For batch processing, use multiple Web Workers to parallelize across CPU cores. Mobile devices are roughly 2-3x slower than desktops.
Memory usage
HEIC decoding requires holding the full uncompressed bitmap in memory. A 12 MP image at 4 bytes per pixel uses 48 MB of RAM. A 48 MP image uses 192 MB. Monitor memory usage when processing multiple files simultaneously in the browser.
Complete Upload Handling Example
A practical implementation that detects HEIC, converts to WebP, and returns a web-ready image:
async function handleImageUpload(file) {
if (isHeicFile(file)) {
// Convert HEIC to WebP via Sharp
const buffer = Buffer.from(await file.arrayBuffer());
const webpBuffer = await sharp(buffer)
.resize(2048, 2048, { fit: 'inside', withoutEnlargement: true })
.webp({ quality: 80 })
.toBuffer();
return { buffer: webpBuffer, mimeType: 'image/webp' };
}
// Non-HEIC images: optimize directly
const buffer = Buffer.from(await file.arrayBuffer());
const webpBuffer = await sharp(buffer)
.resize(2048, 2048, { fit: 'inside', withoutEnlargement: true })
.webp({ quality: 80 })
.toBuffer();
return { buffer: webpBuffer, mimeType: 'image/webp' };
}
Generate multiple format variants at upload time -- AVIF, WebP, and JPG -- to serve via the <picture> element or Accept header negotiation.
Key Takeaways
- Accept HEIC uploads -- iPhone users will send them. Detect by MIME type and file extension.
- Convert on ingest -- transform HEIC to WebP, AVIF, and JPG at upload time, not at delivery time.
- Never serve HEIC -- less than 20% browser support makes it unsuitable for image delivery.
- Use WebP as primary -- 97%+ browser support with strong compression. Add AVIF for maximum savings.
- Offload to Web Workers -- client-side HEIC decoding blocks the main thread for 1-3 seconds per image.
- Set Vary: Accept -- when serving multiple formats from the same URL, prevent cache poisoning.
For format comparison details, see HEIC vs WebP and HEIC vs AVIF. To convert HEIC files without installing software, use HEICify's HEIC to JPG converter or HEIC to PNG converter -- both process files entirely in your browser.
Frequently Asked Questions
Do web browsers support HEIC?
How do I handle HEIC uploads in a web application?
Should I serve HEIC images on my website?
Can JavaScript decode HEIC files in the browser?
Related Guides
HEIC vs AVIF: Next-Gen Image Format Showdown
Compare HEIC and AVIF image formats in depth — compression efficiency, quality, HDR support, browser compatibility, and which next-generation format to choose.
HEIC vs WebP: Which Modern Format Wins?
A comprehensive comparison of HEIC and WebP image formats covering compression efficiency, browser support, quality, features, and when to use each format.
What is HEIC Format? Everything You Need to Know
Learn what HEIC is, why Apple uses it, how it compares to JPG, and the easiest ways to open or convert HEIC files on any device.
Ready to Convert Your Images?
Try our free, browser-based converter tools. No uploads required -- your files never leave your device.