Hi everyone — Nacho here from the BWS (Blockchain Web Services) team. We just shipped IPFS.NINJA, a managed IPFS pinning service, and I want to walk through one of the features I think is genuinely under-discussed in the IPFS world: on-the-fly image optimization served straight from a public IPFS gateway.
Full disclosure: I work on this product. This is a transparent walkthrough from the team that built it.
The problem
IPFS is great at serving immutable content. But if you've ever tried to use IPFS for the image-heavy parts of a real product — NFT galleries, dApp avatars, marketplace thumbnails, blog covers — you've hit the same wall:
- Your CID is the original 4 MB PNG. There is no
?w=400to ask for a thumbnail. - You either pre-generate every variant at upload time (and now you're managing N CIDs per asset), or you serve the full-size file every time and watch your bandwidth quota burn.
- Modern formats like AVIF and WebP? You'd need to encode them yourself before uploading.
This is why most production dApps end up putting a Cloudinary or Imgix in front of IPFS, which kind of defeats the point.
What we built
IPFS.NINJA exposes a public, no-auth image transform endpoint:
GET /image/:cid
Query parameters:
| Param | Default | Description |
|---|---|---|
w |
— | Output width in pixels (max 4096) |
h |
— | Output height in pixels (max 4096) |
format |
— |
webp, jpeg, png, or avif
|
quality |
80 | Compression quality 1-100 (only when format is set) |
fit |
cover |
cover, contain, fill, inside, or outside
|
It's served from api.ipfs.ninja/image/:cid, available on all plans including the free Dharma tier (no API key required for the transform itself), and the responses ship with immutable cache headers — same CID + same params = same bytes forever, perfect for any CDN in front.
Quick examples
Resize to 400px wide as WebP:
curl "https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=400&format=webp"
200x200 JPEG thumbnail at 60% quality:
curl "https://api.ipfs.ninja/image/QmXmCX9S6ANV...?w=200&h=200&format=jpeg&quality=60&fit=cover"
Drop it into HTML
The whole point is that you can use it like any other image CDN. Here's a responsive <img>:
<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"
/>
You store one CID. The browser asks for the size and format it actually needs. The bytes that come back are content-addressed back to your original via the CID in the URL.
Why this matters for NFTs
If you mint with the original artwork's CID as the canonical reference (and you should — that's what gives the asset provenance), you can still render efficient gallery views, thumbnails, and previews:
const tokenImage = `ipfs://${cid}`; // canonical, immutable
const thumb = `https://api.ipfs.ninja/image/${cid}?w=240&h=240&format=webp&quality=70`;
const preview = `https://api.ipfs.ninja/image/${cid}?w=800&format=avif`;
The original artwork stays untouched on IPFS. You just get cheap, on-demand variants for your UI.
A note on framework integration
Next.js <Image>, Nuxt <NuxtImg>, Astro <Image>, and most other framework image components let you plug in a custom loader. You can write a one-liner that maps (src, width, quality) → https://api.ipfs.ninja/image/${cid}?w=${width}&format=webp&quality=${quality} and you've effectively connected your framework's responsive image pipeline to IPFS.
Caching
Responses include immutable cache headers. Because IPFS content is content-addressed, the same CID with the same query parameters always produces the same output. Browsers and CDNs (Cloudflare, Fastly, your own Varnish) can cache these responses indefinitely — no cache busting needed, ever.
Limits and honesty
A few things worth knowing:
- Max output dimensions: 4096px on either axis.
- The transform endpoint is public; if you don't want certain CIDs hot-reachable, don't pin them publicly (or use Nirvana's dedicated gateway with token-based access).
- If you don't pass any params, the request just redirects to the original file.
Try it
- Image Optimization docs: ipfs.ninja/docs/api/image-optimization
- Sign up free (Dharma plan, image optimization included): ipfs.ninja
Questions or edge cases you'd like to see supported (focal point cropping, smart blur for placeholders, etc.) — drop them below. We're actively iterating.
— Nacho, BWS team
Top comments (0)