...

Convert HEIC to JPG Automatically on Upload

An iPhone photo arrives as HEIC and leaves as JPG, converted inside the upload path so every browser gets an image it renders.

The original HEIC stays as the master file. The JPG is the derivative.

heic-to-jpg image/jpeg
# Convert HEIC to JPG on request
output=format:jpg,quality:85/HANDLE

# Or convert on every upload
storeTo: { workflows: ['YOUR_WORKFLOW_ID'] }
Trusted by teams at
SendGrid logo with stylized gray text and overlapping square shapes on the left.
LinkedIn logo followed by the word SlideShare in gray text on a light background.
The word teachable is written in all lowercase, sans-serif letters with a colon between teach and able, in a light purple color on a light background.
A gray Airtable logo featuring a geometric cube design to the left of the word Airtable in bold, modern font.

What HEIC Is

HEIC is the High Efficiency Image Container, an image encoded with HEVC, or H.265, and held in a HEIF container.

HEIF sits in the ISO Base Media File Format family, the same family as MP4, so a single HEIC file holds more than one simple image. It carries 16 bit colour, transparency, depth maps and the image sequences behind Live Photos and burst captures.

Apple made it the default photo format in iOS 11 and macOS High Sierra, and Android has supported HEIF since Android 9. Apple’s support documentation gives HEIF and HEVC as offering better compression than JPEG and H.264 at similar visual quality.

The container and the codec have different licensing. HEIF itself is royalty free, and the HEVC codec inside it carries patent licensing requirements, which is where browser support parts company with it.

What JPG Gives You Instead

JPEG trades features for reach. It carries no transparency, no more than 8 bits a channel and no image sequences, and at similar visual quality a JPEG file can be larger than the HEIC it came from.

What it has is compatibility, which is the one thing a delivery format cannot compromise on. WebP and AVIF compress better and are now widely supported, though neither is as universal as JPEG, so a practical pipeline keeps JPG as the baseline and serves the newer formats where the browser accepts them.

containerHEIF, ISO/IEC 23008-12
codecHEVC, H.265
file familyISO Base Media File Format
MIME, single imageimage/heic, image/heif
MIME, sequenceimage/heic-sequence, image/heif-sequence
Apple default sinceiOS 11, 2017
Android support sinceAndroid 9, 2018
browser usage sharearound 15%

Usage share for HEIF and HEIC from caniuse.com as of 2026. JPEG is standardised separately as ISO/IEC 10918-1 and ITU-T T.81, lossy, 8 bit colour, and readable by effectively every browser and image library.

Where a HEIC File Stops Rendering

Displaying HEIC needs an HEVC decoder. Three layers of a typical stack are missing one, and each fails differently.

In the browser

Chrome, Firefox and Edge ship no HEVC decoder, so an img pointing at a HEIC file shows a broken image or offers a download. Safari 17 and later renders HEIC and HEIF natively on supported macOS and iOS versions.

In server side image processing

Image libraries reach HEIC through extra packages such as libheif with an HEVC decoder. A default server image without them fails at thumbnail generation and at any other processing step.

On the operating system

Windows opens HEIC once the HEIF Image Extensions are installed alongside a separate HEVC Video Extensions package, which puts two dependencies in front of one photo.

Caniuse’s HEIF/HEIC table records the format as offering better compression than WebP, JPEG, PNG and GIF, and as complex and expensive to license. A W3C Breakouts Day 2026 session on HEIF support in browsers drew one of the event’s largest audiences and closed on discussion rather than adoption, and the Firefox feature request for HEIF support has been open since 2017.

Where in the Upload Path the Conversion Happens

Three points in the path can produce the JPG. They differ in who pays for the conversion and how often it runs.

01

Before the upload

The browser or the mobile app converts on the device. That ships an HEVC decoder in JavaScript or WebAssembly to every user, and the conversion depends on that code loading.

02

When the image is requested

The HEIC is stored as it arrived and converted on first request. The first reader pays the conversion cost, and the result caches for everyone after them.

03

When the image is uploaded

Conversion runs once inside the upload path. The HEIC stays as the master file, the JPG is generated a single time, and every later request reads a file that already exists.

Filestack covers the second and third of these directly. On the fly transformation puts the instruction in the CDN URL and caches the result. A Workflow runs the conversion when the file is uploaded and stores the JPG as its own file. A backend that wants to drive the conversion itself uses the SDK for the same processing task.

Three Ways to Convert HEIC With Filestack

All three run the same Processing Engine task. What changes is when the conversion happens and whether the JPG is stored.

An iPhone photo is captured as HEIC, uploaded through the picker to storage, converted by the Processing Engine with a webhook on completion, then delivered over the CDN and rendered in a browser as JPG.
CDN cdn.filestackcontent.com
/
Task output=format:jpg,quality:85
/
Handle HANDLE
# Convert HEIC to JPG on request
GET https://cdn.filestackcontent.com/output=format:jpg,quality:85/HANDLE

# Convert AND store a new JPG file
GET https://cdn.filestackcontent.com/output=format:jpg,quality:85/store/HANDLE

# With app security enabled
GET https://cdn.filestackcontent.com/security=p:POLICY,s:SIGNATURE/output=format:jpg/HANDLE

# Deliver WebP where supported, JPG otherwise
GET https://cdn.filestackcontent.com/output=format:jpg/auto_image/HANDLE
// Picker: accept HEIC and trigger the conversion Workflow
// on every upload
import * as filestack from 'filestack-js';

const client = filestack.init('YOUR_API_KEY');

client.picker({
  accept: ['image/*'], // includes image/heic, image/heif
  storeTo: { workflows: ['YOUR_WORKFLOW_ID'] },
  onFileUploadFinished: (file) => {
    // file.handle, file.url, file.mimetype ('image/heic'), file.size
    saveOriginalHandle(file.handle);
  }
}).open();

// The same Workflow can be triggered with a direct SDK upload
client.upload(fileBlob, {}, { workflows: ['YOUR_WORKFLOW_ID'] });
// filestack-js: returns the transformation URL
const url = client.transform(handle, { output: { format: 'jpg' } });

// Chain the store task to save the converted file:
// output=format:jpg/store/HANDLE
// The response includes information about the new file,
// such as its handle, URL, size, and type.

All three work from the same handle the Picker or the Upload API produced, so a pipeline can start on the CDN URL and move to a Workflow without re-uploading the originals. Applications with security enabled allow convert, store and runWorkflow in the policy and signature.

One HEIC File Through the Pipeline

The file uploads, its metadata is read, the conversion runs on the fly and stores the JPG, and the result’s metadata is read again.

The original HEIC

call /metadata/
filename classic-car.heic
size 1,960,764 bytes
mimetype image/heic
browser preview not rendered

The converted JPG

task output=format:jpg,quality:85/store/
filename classic-car.jpg
size 1,681,309 bytes
mimetype image/jpeg
browser preview displays

The original file stays unchanged. Only the format of the delivered file changes.

Conversion Approaches Side by Side

A decision guide rather than a ranking. Most pipelines end up using two of the three for different jobs.

  Client side, browser or app Filestack CDN URL Filestack Workflow
Trigger Before upload, on the device First request for the JPG URL Automatically on upload
Where it runs The user's CPU, JS or WASM decoder Filestack Processing Engine Filestack Processing Engine
Consistency Varies by browser and device Same for every request Same for every upload
Original preserved Only if uploaded as well Yes, the handle is unchanged Yes, the original is kept
JPG persisted Locally Cached, not stored separately Yes, through the store task
Latency Slow on low end devices First request converts, then cached Asynchronous, result on a webhook
Setup Ship a decoder library Change the URL Add a Workflow ID to storeTo
Best for Offline first apps One off derivatives Repeatable automatic conversion

Straight talk: an offline first app that has to produce a JPG with no network is the case client side conversion wins outright, and shipping the decoder is the price of that. Everything that reaches a server is cheaper to convert once, upstream.

Edge Cases in a HEIC to JPG Conversion

Four properties of HEIC that JPEG handles differently. Each is a setting decided once, in the Workflow or the URL template.

What happens to a Live Photo when it becomes a JPG?

A Live Photo HEIC holds a main still image and a motion sequence. Conversion extracts the primary still and delivers that as the JPG. The motion sequence stays in the original HEIC, since JPG carries a single image. The photo converts; the Live Photo experience lives in the master file.

Why does the converted JPG come out sideways?

iPhones record orientation in EXIF metadata rather than rotating the pixels. A client that reads EXIF orientation loosely then shows the image on its side. The Filestack Processing Engine handles this explicitly with rotate=deg:exif, which applies the recorded orientation during processing.

What happens to HDR and higher bit depth colour?

HEIC carries higher bit depth and HDR data, and a JPEG pipeline targets 8 bit output, so the extra colour information maps down into sRGB. Very bright highlights carry slightly less detail after conversion. That is the expected result of moving from HDR HEIC to standard JPEG.

Which JPEG quality value should the pipeline use?

The output task takes a quality value from 1 to 100, and quality:input carries the source setting through. Around 80 to 90 suits web delivery. The compress task reduces the file further where size matters more than the last of the detail.

Practices for a HEIC Upload Pipeline

Seven settings that keep every HEIC upload converting the same way, whichever device produced it.

Allow HEIC
accept: ['image/*']
The Picker takes image/heic and image/heif.
Convert on upload
storeTo.workflows
Conversion belongs to the upload, not to a later job.
One settings home
Workflow or URL template
Format, quality and orientation stay together.
Keep the original
master file
WebP and AVIF come from the same HEIC later.
Expect async
status: Finished
Save the handle first, update when the webhook lands.
auto_image delivery
auto_image
WebP to browsers that take it, JPEG to the rest.
Signed pipeline
HMAC-SHA256, FS-Signature
Policy and signature on requests, verified webhooks.
An iPhone photo is captured as HEIC, uploaded through the picker to storage, converted by the Processing Engine with a webhook on completion, then delivered over the CDN and rendered in a browser as JPG.

What the Workflow Sends Back

The Workflow runs asynchronously, so the upload finishes before the JPG exists. Filestack posts the result to your endpoint when it is ready.

Large HEIC files ride the same multipart uploader, with 6 MB parts, 3 concurrent parts and up to 10 retries with exponential backoff. Intelligent Ingestion covers the unstable connections, which is the subject of chunked file uploads with resume support.

Read results for the new JPG handle and sources for the HEIC it came from. Failed deliveries retry after 5 minutes, 30 minutes and 12 hours, and workflow_status=job_id answers a direct poll.

fs.workflow webhookstatus Finished
{
  "action": "fs.workflow",
  "text": {
    "workflow": "WORKFLOW_UUID",
    "status": "Finished",
    "sources": ["ORIGINAL_HEIC_HANDLE"],
    "results": {
      "output_1755500000000": {
        "data": {
          "filetype": "jpg",
          "mimetype": "image/jpeg",
          "handle": "NEW_JPG_HANDLE",
          "size": 412884,
          "url": "https://cdn.filestackcontent.com/NEW_JPG_HANDLE"
        }
      }
    }
  }
}

Frequently Asked Questions

How do I convert HEIC to JPG automatically on upload?

Create a Filestack Workflow with an output task set to jpg and a store task, then pass its ID through the Picker as storeTo.workflows or through the SDK as storeOptions.workflows. Every upload is converted and stored, and the new handle arrives on your webhook.

Why does my HEIC image not display in Chrome?

Chrome, Firefox and Edge ship no HEVC decoder, and HEIC images are HEVC encoded, so those browsers render nothing. Safari 17 and later supports HEIC and HEIF natively, including on iOS 17. Converting to JPG, WebP or AVIF covers every browser.

Can Filestack convert HEIC files?

Yes. The Filestack Processing Engine accepts HEIC and HEIF input and converts it with the output task, such as output=format:jpg or output=format:png. The conversion runs from a CDN URL, inside a Workflow, or through client.transform().

What is the Filestack URL to convert HEIC to JPG?

Request cdn.filestackcontent.com with output=format:jpg,quality:85 ahead of the handle. Adding /store/ before the handle persists the converted JPG as a new file. Applications with security enabled also carry security=p:POLICY,s:SIGNATURE on the request.

Does converting HEIC to JPG lose quality?

A little. JPEG is lossy and holds 8 bit colour, while HEIC can carry 10 bit, 16 bit and HDR data. At quality 85 to 95 the difference is hard to see on a typical web image. Keeping the HEIC preserves the original.

How do I handle Live Photos when converting?

A Live Photo HEIC holds a primary still image alongside an image sequence. Conversion extracts the primary still and delivers it as the JPG. The motion sequence stays in the original file, since JPG carries single images.

Is the HEIC conversion synchronous?

It depends on the approach. A CDN URL converts as part of the request and the result caches at the edge. A Workflow runs asynchronously, so the upload finishes first and the result arrives through the fs.workflow webhook or a workflow_status poll.

Should I convert HEIC to JPG or to WebP and AVIF?

JPG is the universal baseline, since browser support for it is effectively complete. WebP and AVIF go to the browsers that accept them. The Filestack auto_image task picks a supported encoding from the request, so one URL covers both.