Image Optimization API

A single GET endpoint that fetches, resizes, and converts any public image URL on the fly. Authentication is required — every request must include a Bearer token.

Endpointhttps://imgoptimizer.com/api/img
MethodGET
AuthBearer token
Rate limit60 req / minute

Authentication

All requests to /api/img require a valid API token. Requests without a token are rejected with 401 Unauthorized.

1

Sign in with Google

Open the ImgOptimizer editor and click Sign in in the top-right corner.

2

Get your API token

After signing in, click your profile photo (top-right). A modal will show your personal API token. Click Copy to copy it to your clipboard.

3

Include the token in every request

Send it as an HTTP header:

Authorization: Bearer YOUR_API_TOKEN

Or as a query parameter (less secure, avoid in production):

https://imgoptimizer.com/api/img?url=...&token=YOUR_API_TOKEN

Token security: Your token is tied to your account email and signed with a server secret. Keep it private — anyone with your token can use the API on your behalf. Tokens are stable and do not expire unless the server secret is rotated.

Query Parameters

NameTypeRequiredDescription
urlstringrequiredPublic URL of the source image.
wnumberoptionalOutput width in pixels. Default: source width.
hnumberoptionalOutput height in pixels. Default: source height.
fstringoptionalOutput format: jpeg | jpg | webp | avif | png. Default: webp.
qnumberoptionalQuality 1–100 (ignored for PNG). Default: 82.
fitstringoptionalResize mode: contain | cover | fill | pad | inside. Default: inside (shrink-only, never upscale).
bgstringoptionalBackground/pad color as hex (e.g. %23ffffff). Used when fit=contain or fit=pad. Default: #ffffff.
cxnumberoptionalCrop X offset 0–1 relative to source width. Default: 0.
cynumberoptionalCrop Y offset 0–1 relative to source height. Default: 0.
cwnumberoptionalCrop width 0–1 relative to source width. Default: 1.
chnumberoptionalCrop height 0–1 relative to source height. Default: 1.

Quick Start

Replace YOUR_API_TOKEN with your token and https://example.com/photo.jpg with your image URL.

curl "https://imgoptimizer.com/api/img?url=https://example.com/photo.jpg&w=800&h=600&f=webp&q=80" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ --output result.webp

Examples

1Basic resize to 400×300, WebP

cURL

curl "https://imgoptimizer.com/api/img?url=https://example.com/photo.jpg&w=400&h=300&f=webp&q=80" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ --output result.webp

JavaScript (fetch)

const res = await fetch( "https://imgoptimizer.com/api/img?url=https://example.com/photo.jpg&w=400&h=300&f=webp&q=80", { headers: { Authorization: "Bearer YOUR_API_TOKEN" } } ); const blob = await res.blob();

2Square crop for Instagram (cover fit)

cURL

curl "https://imgoptimizer.com/api/img?url=https://example.com/photo.jpg&w=1080&h=1080&f=avif&q=85&fit=cover" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ --output instagram.avif

JavaScript (fetch)

const res = await fetch( "https://imgoptimizer.com/api/img?url=https://example.com/photo.jpg&w=1080&h=1080&f=avif&q=85&fit=cover", { headers: { Authorization: "Bearer YOUR_API_TOKEN" } } ); const blob = await res.blob();

3Thumbnail with white padding (pad fit)

cURL

curl "https://imgoptimizer.com/api/img?url=https://example.com/photo.jpg&w=200&h=200&f=jpeg&q=75&fit=pad&bg=%23ffffff" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ --output thumb.jpg

JavaScript (fetch)

const res = await fetch( "https://imgoptimizer.com/api/img?url=https://example.com/photo.jpg&w=200&h=200&f=jpeg&q=75&fit=pad&bg=%23ffffff", { headers: { Authorization: "Bearer YOUR_API_TOKEN" } } ); const blob = await res.blob();

4Lossless PNG

cURL

curl "https://imgoptimizer.com/api/img?url=https://example.com/logo.png&w=512&h=512&f=png" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ --output logo.png

JavaScript (fetch)

const res = await fetch( "https://imgoptimizer.com/api/img?url=https://example.com/logo.png&w=512&h=512&f=png", { headers: { Authorization: "Bearer YOUR_API_TOKEN" } } ); const blob = await res.blob();

Using in Next.js

Fetch from a server component or API route so the token stays server-side.

// app/api/image/route.ts (server-side proxy — token never exposed to browser) export async function GET(req: Request) { const { searchParams } = new URL(req.url); const photoUrl = searchParams.get("url"); const res = await fetch( `https://imgoptimizer.com/api/img?url=${encodeURIComponent(photoUrl!)}&w=800&h=600&f=webp&q=80`, { headers: { Authorization: `Bearer ${process.env.IMAGE_API_TOKEN}` } } ); return new Response(res.body, { headers: { "Content-Type": res.headers.get("Content-Type") ?? "image/webp" }, }); }

Using in Python

import requests TOKEN = "YOUR_API_TOKEN" url = "https://example.com/photo.jpg" res = requests.get( "https://imgoptimizer.com/api/img", params={"url": url, "w": 800, "h": 600, "f": "webp", "q": 80}, headers={"Authorization": f"Bearer {TOKEN}"}, ) res.raise_for_status() with open("output.webp", "wb") as f: f.write(res.content) print(f"Saved {len(res.content):,} bytes")

Error Responses

StatusMeaning
401Missing or invalid API token — sign in and copy your token from the editor
400Missing or invalid parameters (e.g. no url, unsupported format)
403Request origin not allowed (CORS)
429Rate limit exceeded (60 req/min) — wait 60 s and retry. Also returned when the free plan monthly limit (500 req) is reached — upgrade to Pro.
502Source image could not be fetched from the given URL
500Image processing failed

Error response body (JSON):

{ "error": "Descriptive error message here" }

Optimize → Upload to S3

Fetch an optimized image from the API and upload it directly to S3 using a presigned PUT URL. The image flows from the API response straight to your bucket — no extra storage needed on your side.

1 — Generate a presigned PUT URL (server-side)

// Node.js — AWS SDK v3 import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const presignedUrl = await getSignedUrl( new S3Client({ region: "us-east-1" }), new PutObjectCommand({ Bucket: "my-bucket", Key: "images/output.webp", ContentType: "image/webp", }), { expiresIn: 300 } // URL valid for 5 minutes );

2 — Optimize and upload in one pass (Node.js)

const TOKEN = process.env.IMAGE_API_TOKEN; // Step 1: fetch the optimized image const res = await fetch( "https://imgoptimizer.com/api/img?url=https://example.com/photo.jpg&w=1200&f=webp&q=85", { headers: { Authorization: `Bearer ${TOKEN}` } } ); const blob = await res.arrayBuffer(); // Step 2: PUT directly to S3 (no temp file) await fetch(presignedUrl, { method: "PUT", body: blob, headers: { "Content-Type": "image/webp" }, }); const publicUrl = presignedUrl.split("?")[0]; // strip query params console.log("Uploaded:", publicUrl);

Browser upload (after client-side optimization)

// Works with the editor's "↑ Upload to S3" button flow, // or call directly after processing: async function uploadToS3(blob: Blob, presignedUrl: string): Promise<string> { const res = await fetch(presignedUrl, { method: "PUT", body: blob, headers: { "Content-Type": blob.type }, }); if (!res.ok) throw new Error(`Upload failed: ${res.status}`); return presignedUrl.split("?")[0]; // public S3 URL }

Tip: The editor UI has a built-in ↑ Upload to S3 button. After optimizing an image, click it, paste a presigned PUT URL, and the browser uploads directly — no server roundtrip.

Notes

  • The source image URL must be publicly accessible (no auth required on the source).
  • EXIF metadata is automatically stripped from all output formats.
  • JPEG output uses progressive encoding by default (better perceived load speed).
  • PNG output is always lossless — the q parameter is ignored.
  • The bg hex value must be URL-encoded: #ffffff%23ffffff.
  • AVIF encoding runs server-side via WASM — it works regardless of client browser support.
  • Prefer sending tokens via the Authorization header rather than the ?token= query param to avoid tokens appearing in server logs.

Try it visually

Sign in, grab your token, and use the interactive editor to build and preview API requests.

Open ImgOptimizer Editor