WebP to JPG API
POST a .webp file to /v2/convert/webp/to/jpg and get a baseline JPEG back as base64 in the JSON. It reads lossy, lossless and transparent WebP, and can scale the picture down in the same request.
- Endpoint
- POST /v2/
convert/ webp/ to/ jpg - Accepts
- webp
- 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/webp/to/jpg \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@spring-tuneup-banner.webp \
--form-string ImageWidth=1200 \
--form-string ImageQuality=80 \
-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/webp/to/jpg",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("spring-tuneup-banner.webp", "rb"))],
data={
"ImageWidth": "1200",
"ImageQuality": "80",
},
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 = "spring-tuneup-banner.webp";
form.append("File", new Blob([await readFile(file)]), file);
form.append("ImageWidth", "1200");
form.append("ImageQuality", "80");
const url = "https://api.pdfconversionapi.com/v2/convert/webp/to/jpg";
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": "spring-tuneup-banner.jpg",
"FileExt": "jpg",
"FileSize": 73060,
"FileData": "/9j/4AAQSkZJRgABAgAAAQAB…"
}
]
}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
- spring-tuneup-banner.webp (37 KB)
- Output
- spring-tuneup-banner.jpg (71 KB)
- Source
- Drawn for this site: a banner for a fictional business, saved as lossy WebP (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 |
|---|---|
ImageQualityinteger, default 85 | Quality setting for the JPEG encoder. We use 85 if you don't send one; ConvertAPI's documented default is 75.Values: 1–100 |
ImageWidthinteger | Output width in pixels. The sample sends 1200, so the 1600 × 900 banner comes back 1200 × 675.Values: 1–20000 |
ImageHeightinteger | Output height in pixels. On its own it sets the height and derives the width; together with ImageWidth it defines a maximum box.Values: 1–20000 |
ScaleProportionsboolean, default true | false lets the picture be distorted to fill the exact ImageWidth × ImageHeight. Sent without a width or height, it is accepted and changes nothing. |
ScaleIfLargerboolean, default false | true turns the resize into a downscale-only step, so a WebP narrower than ImageWidth keeps its own size. It has no effect unless a width or height is in the request. |
ScaleImageboolean, default true | false cuts a region out of the top-left corner at the requested width and height, with no scaling. Without a width or height, the WebP keeps its full size. |
AlphaColorstring, default white | Matte color for WebP files that carry an alpha channel. Opaque WebPs, like the sample, are not affected.Values: A color name (white, black, red, green, blue, gray), #RRGGBB or R,G,B |
BackgroundColorstring, default white | Read as the matte color when AlphaColor is absent.Values: Same as AlphaColor |
ColorSpaceenum, default rgb | gray writes a one-channel grayscale JPEG: the full-size banner went from 122,718 to 79,969 bytes at the default quality. monochrome turns each pixel black or white before the JPEG encode (84,934 bytes). cmyk returns 400.Values: rgb, gray, monochrome |
ImageResolutioninteger | The DPI recorded in the JPEG header. Pixels are not resampled: the banner stays 1600 × 900 at 72 or 200. Left out, the header has no unit (density 1:1); ConvertAPI documents 200.Values: 10–800 |
ImageInterpolationboolean, default false | Accepted with true or false. Resizing always uses a Lanczos3 filter, so the sample request gave the same 73,060 bytes either way. |
FileNamestring | Base name for the result. spring-tuneup-banner.webp becomes spring-tuneup-banner.jpg unless you set this. |
StoreFileboolean, default false | true keeps the JPEG on our side for 3 hours and returns a download URL in Files[].Url instead of FileData. |
What carries over, and what doesn't
Kept
- Every WebP flavor we tested: lossy (VP8), lossless (VP8L) and the extended format with alpha (VP8X)
- The decoded picture itself: for the sample, our decode matched dwebp from libwebp 1.6.0 on every pixel before the JPEG step
- Aspect ratio when you resize with one dimension (1600 × 900 became 1200 × 675)
- Color detail at full resolution: the JPEG is written without chroma subsampling
- Upright pictures: the EXIF Orientation tag is applied to the pixels (a 300 × 200 test WebP tagged 6 came back 200 × 300), and the tag is not copied
Lost or not yet supported
- Size. JPEG is less efficient than WebP, so the result is usually bigger: the 37,538-byte sample came back as 73,060 bytes even after being scaled down to 1200 px.
- A generation of quality. The JPEG is a second lossy encode on top of the WebP's own compression; if you still have the original PNG or camera file, convert that instead.
- Frames after the first in animated WebP.
- ICC profiles, EXIF and XMP chunks. The JPEG carries only a JFIF header, with a DPI value only when you send
ImageResolution. - Alpha. Transparent areas are filled with
AlphaColor, white by default.
Limits
- One WebP per request.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- Decoded images are limited to 100,000,000 pixels; larger ones return 413 before any pixels are decoded.
- Resize targets from 1 to 20,000 px per side.
- 120 seconds per conversion, then 504.
Where teams use it
Images saved from the web
Pictures saved from a browser often arrive as .webp, because many sites serve that format. Convert them on upload when the next step in your pipeline only takes JPEG.
One format in your media library
Accept whatever people upload, and store a JPEG copy next to the original so every downstream job reads the same format. Set ImageWidth to cap the stored size while you are at it.
Stills from animated WebP
Send an animated WebP and you get its first frame as a JPEG, which works as a poster image or a thumbnail in a list view.
Questions
Why is the JPEG bigger than the WebP I uploaded?
WebP stores a similar-looking image in fewer bytes than JPEG. Our encoder turns the decoded pixels into a JPEG at quality 85 by default. The sample on this page went from 37,538 bytes to 73,060 bytes at quality 80 while also shrinking to 1200 px wide. Lower ImageQuality or set ImageWidth if size matters more than detail.
Does the conversion change the colors?
Not in the decode step. For the sample WebP, our decoded pixels were identical to the output of dwebp, the reference decoder in libwebp 1.6.0. What changes comes after: the JPEG encode (quality 85 unless you send ImageQuality), and embedded color profiles, which are not carried over. A WebP tagged Display P3 keeps its pixel values, so its colors look duller in viewers that assume sRGB.
What happens with an animated WebP?
You get one JPEG of the first frame, with the request still returning 200. There is no option to pick another frame or to get every frame as a separate file.
Is the EXIF orientation of a WebP applied?
Yes. Before the JPEG is written, the pixels are turned the way the WebP's EXIF Orientation tag says, so our 300 × 200 test file tagged 6 (turn 90° clockwise) came back 200 × 300 and the right way up. The tag itself is not copied, so viewers won't turn the JPEG a second time. Rotate is not read on this route.
Does it accept WebP files with transparency?
Yes. The alpha channel is decoded and then flattened, because JPEG can't hold it. A transparent product image converted with no options gets a white background; send AlphaColor=#202020 or any other color to change it.
Convert your first WebP file in a minute.