HEIF to GIF API
POST a .heif to /v2/convert/heif/to/gif and get a still GIF89a with a 256-color palette. GIF transparency is on or off, so only fully clear pixels stay clear: the sticker's soft shadow, made of partly transparent pixels (alpha 1 to 112), came out as an opaque dark blob.
- Endpoint
- POST /v2/
convert/ heif/ to/ gif - Accepts
- heif
- Sample timing
- 72 ms median of 5 runsHow we measure
- Request size
- Up to 10 MB on the Free plan or 100 MB on paid plans, all files together
Request and response
Every sample below ran against the API before this page was published. Set PDFCONVERSIONAPI_KEY to your key and run it as is.
curl -sS -X POST \
https://api.pdfconversionapi.com/v2/convert/heif/to/gif \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@succulent-sticker.heif \
-o response.json
# FileData is base64. Save the first file in converted/,
# or print the JSON error.
if jq -e '.Files' response.json > /dev/null; then
mkdir -p converted
name=$(jq -r '.Files[0].FileName' response.json)
jq -r '.Files[0].FileData' response.json \
| base64 --decode > "converted/$name"
else
cat response.json
fiimport base64
import os
import requests
key = os.environ["PDFCONVERSIONAPI_KEY"]
response = requests.post(
"https://api.pdfconversionapi.com/v2/convert/heif/to/gif",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("succulent-sticker.heif", "rb"))],
timeout=180,
)
result = response.json()
if not response.ok:
raise SystemExit(f"{result['Code']}: {result['Message']}")
os.makedirs("converted", exist_ok=True)
for file in result["Files"]:
path = os.path.join("converted", file["FileName"])
with open(path, "wb") as out:
out.write(base64.b64decode(file["FileData"]))
print(path, file["FileSize"], "bytes")
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
const form = new FormData();
const file = "succulent-sticker.heif";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/heif/to/gif";
const key = process.env.PDFCONVERSIONAPI_KEY;
const response = await fetch(url, {
method: "POST",
headers: { Authorization: `Bearer ${key}` },
body: form,
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.Code}: ${result.Message}`);
}
await mkdir("converted", { recursive: true });
for (const file of result.Files) {
const path = join("converted", file.FileName);
await writeFile(path, Buffer.from(file.FileData, "base64"));
console.log(path, file.FileSize, "bytes");
}
{
"ConversionCost": 1,
"ConversionTime": 0.072,
"Files": [
{
"FileName": "succulent-sticker.gif",
"FileExt": "gif",
"FileSize": 16418,
"FileData": "R0lGODlhQAFAAYAAAAAAAAAA…"
}
]
}Response from our test run on 2026-11-03. ConversionTime shows the median of 5 runs. FileData is shortened here; the real response carries the whole file as base64.
The sample, converted
The same file the code sends. Download the input and the output and compare them yourself.

- Input
- succulent-sticker.heif (11 KB)
- Output
- succulent-sticker.gif (16 KB)
- Source
- A potted succulent sticker that we drew ourselves, with a transparent background and a soft shadow, saved as a 320 x 320 HEIF with an alpha plane. (CC0-1.0). How it was made
- Made by
- 2026-11-04, API build
9eeeb0640aba
Parameters
Send these as form fields next to the file. Names are case-insensitive. If you set one of the documented options below that we don't support yet, the request fails with a 400 that names it instead of returning a file made without it.
| Parameter | What it does |
|---|---|
ImageWidthinteger | Scales before the palette is built; 200 gave 8,605 bytes.Values: 1–20000 |
ImageHeightinteger | Target height, or a box with ImageWidth.Values: 1–20000 |
ScaleProportionsboolean, default true | false uses both sizes as given. |
ScaleIfLargerboolean, default false | true never enlarges. |
ScaleImageboolean, default true | false crops the top-left area. |
ColorSpaceenum, default default | gray (16,340 bytes) or monochrome (2,471 bytes); clear areas stay transparent in both.Values: default, rgb, gray, monochrome |
TransparentColorstring | Also clears every pixel of exactly this color. #C4623B, the pot's main clay color, cut 5,931 pixels out of the pot.Values: #RRGGBB, R,G,B or a basic color name |
FileNamestring | Base name for the .gif. |
StoreFileboolean, default false | true returns a 3-hour link. |
What carries over, and what doesn't
Kept
- Fully clear pixels: all 72,482 became the GIF's transparent index
- The pot and leaves, in 235 distinct colors
- One frame at 320 × 320, 16,418 bytes
Lost or not yet supported
- Soft edges. All 11,811 partly clear pixels turned fully opaque in their stored color, which is near black for the shadow, so it became a dark blob.
- A thin dark fringe around the leaves, from the same cause.
- Colors: 6,079 in the decoded sticker, 235 in the GIF.
- Tones of Display P3-tagged HEIF files, which the decoder stretches.
Limits
- One HEIF per request and one frame per GIF.
- Up to 100,000,000 pixels; requests up to 10 MB on the Free plan or 100 MB on paid plans; 120 seconds per conversion.
- A GIF side can't exceed 65,535 px: a 70,000 × 64 image sent as .heif returned 413 'GIF images can be at most 65,535 pixels on a side, and this one is 70,000×64'. On the HEIC route, 65,535 px converted and 65,536 got the same 413.
- AV1-coded HEIF (AVIF) returns 422.
Where teams use it
Stickers for places that only take GIF
Chat tools, forums and email builders that accept GIF but not HEIF can show a cut-out sticker this way. Hard-edged artwork with no soft shadow converts best.
Checking how a graphic degrades in GIF
Converting a HEIF design shows at once which parts depend on partial transparency: on the sample, the shadow and the leaf edges.
Questions
Why did the shadow turn black?
GIF has a single transparent color, not levels of transparency. Pixels with any opacity at all are drawn solid in their stored color, and a shadow's stored color is dark. Only the 72,482 pixels that were completely clear kept their transparency.
How do I keep the shadow looking right?
Flatten it first. Convert with /v2/convert/heif/to/pnm and AlphaColor=#FFFFFF, then send that to /v2/convert/pnm/to/gif. The sample's shadow became a soft gray on white; the GIF then has no transparent areas.
Are unread options refused here?
No. HEIF to GIF accepts options it doesn't use, such as ImageQuality, and returns the same file. Only invalid values of options it does read, like ImageWidth=0, return 400.
Convert your first HEIF file in a minute.