Skip to content

Image Optimization

Transform and optimize images served from IPFS on-the-fly using query parameters. This is a public endpoint that requires no authentication.

Optimize Image

GET https://api.ipfs.ninja/image/:cid

Returns the image at the given CID, transformed according to the provided query parameters. If no transform parameters are supplied, the request 302-redirects to the original image on the IPFS gateway.

Path parameters

ParameterTypeRequiredDescription
cidstringYesThe IPFS content identifier of the image.

Query parameters

ParameterTypeDefaultDescription
wintegerOutput width in pixels. Range: 1–4096. Values ≤ 0 or non-numeric are ignored.
hintegerOutput height in pixels. Range: 1–4096. Values ≤ 0 or non-numeric are ignored.
formatstringOutput format: webp, jpeg, png, or avif. Case-sensitive (lowercase). Unknown values are ignored.
qualityinteger80Compression quality, 1–100. Applies to webp, jpeg, and avif only. png is lossless and ignores this.
fitstringcoverHow the image should fit the dimensions: cover, contain, fill, inside, or outside.

Note: the parameter is quality, not q. Common shorthand aliases (q, width, height, fmt) are not recognized.

A request that supplies none of w, h, or format is treated as a no-op and 302-redirects to the original image. quality and fit alone do not trigger a transform.

Fit modes

ModeBehavior
coverCrop to cover both dimensions (default).
containFit within both dimensions, preserving aspect ratio. May leave empty space (transparent or black depending on format).
fillStretch to fill both dimensions exactly. May distort the image.
insideLike contain, but only scales down, never up.
outsideLike cover, but only scales down, never up.

Upscaling

The transformer never enlarges an image beyond its source dimensions. If you request w=2000 for a 1200px-wide source, the output will be 1200px wide. This applies to all fit modes.

Response

StatusWhenBody
200Transform produced on this request.Binary image bytes. Content-Type matches the requested format.
302No transform params supplied, or a previously transformed result is already cached.Location header points to the original image or the cached result on https://ipfs.ninja/image-cache/....
400cid path parameter missing.{ "error": "cid required" }
404CID not found on the gateway.{ "error": "CID not found" }
500Unexpected error (corrupt image, transform failure, etc.).{ "error": "<message>" }

All 200 and 302-cache responses are served with Cache-Control: public, max-age=31536000, immutable. See Caching below.

Example requests

Resize to 400px wide, convert to WebP:

bash
curl "https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=400&format=webp"

Resize and crop to 200×200 thumbnail as JPEG at 60% quality:

bash
curl "https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=200&h=200&format=jpeg&quality=60&fit=cover"

Square thumbnail with letterboxing instead of cropping:

bash
curl "https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=200&h=200&format=png&fit=contain"

Convert format only, no resize (useful for serving AVIF/WebP versions of legacy JPEGs):

bash
curl "https://api.ipfs.ninja/image/QmXmCX9S6ANV...?format=avif&quality=70"

Cap maximum width without forcing height (preserves aspect ratio):

bash
curl "https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=1200&format=webp"

Using in HTML

Reference optimized images directly in img tags:

html
<img
  src="https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=800&format=webp&quality=75"
  alt="Optimized IPFS image"
/>

Serve different sizes with srcset:

html
<img
  srcset="
    https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=400&format=webp 400w,
    https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=800&format=webp 800w,
    https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=1200&format=webp 1200w
  "
  sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
  src="https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=800&format=webp"
  alt="Responsive IPFS image"
/>

Modern format negotiation with <picture> (AVIF → WebP → JPEG fallback):

html
<picture>
  <source
    type="image/avif"
    srcset="https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=800&format=avif&quality=60"
  />
  <source
    type="image/webp"
    srcset="https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=800&format=webp&quality=75"
  />
  <img
    src="https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=800&format=jpeg&quality=80"
    alt="IPFS image with format fallback"
  />
</picture>

CSS background-image:

css
.hero {
  background-image: url("https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=1600&format=webp&quality=70");
}

Using with Next.js

As a custom loader for next/image:

js
// loaders/ipfs.js
export default function ipfsLoader({ src, width, quality }) {
  return `https://api.ipfs.ninja/image/${src}?w=${width}&format=webp&quality=${quality || 75}`;
}
jsx
import Image from "next/image";
import ipfsLoader from "@/loaders/ipfs";

<Image
  loader={ipfsLoader}
  src="QmXmCX9S6ANV..."
  alt="IPFS image"
  width={800}
  height={600}
/>;

Caching

Responses are served with Cache-Control: public, max-age=31536000, immutable. Since IPFS content is content-addressed, the same CID with the same parameters always produces the same output, so browsers and CDNs can cache responses indefinitely.

Cached transforms are stored in S3 keyed by the full parameter set (cid, w, h, format, quality, fit). Subsequent requests with the same parameters return a 302 redirect to the CloudFront-fronted cache (https://ipfs.ninja/image-cache/...) rather than re-running the transform. Different parameter combinations produce different cache entries.

Availability

Image optimization is available on all plans, including the free Dharma plan.