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.
Authentication
All requests to /api/img require a valid API token. Requests without a token are rejected with 401 Unauthorized.
Sign in with Google
Open the ImgOptimizer editor and click Sign in in the top-right corner.
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.
Include the token in every request
Send it as an HTTP header:
Authorization: Bearer YOUR_API_TOKENOr as a query parameter (less secure, avoid in production):
https://imgoptimizer.com/api/img?url=...&token=YOUR_API_TOKENToken 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
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | required | Public URL of the source image. |
| w | number | optional | Output width in pixels. Default: source width. |
| h | number | optional | Output height in pixels. Default: source height. |
| f | string | optional | Output format: jpeg | jpg | webp | avif | png. Default: webp. |
| q | number | optional | Quality 1–100 (ignored for PNG). Default: 82. |
| fit | string | optional | Resize mode: contain | cover | fill | pad | inside. Default: inside (shrink-only, never upscale). |
| bg | string | optional | Background/pad color as hex (e.g. %23ffffff). Used when fit=contain or fit=pad. Default: #ffffff. |
| cx | number | optional | Crop X offset 0–1 relative to source width. Default: 0. |
| cy | number | optional | Crop Y offset 0–1 relative to source height. Default: 0. |
| cw | number | optional | Crop width 0–1 relative to source width. Default: 1. |
| ch | number | optional | Crop 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.webpExamples
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.webpJavaScript (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.avifJavaScript (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.jpgJavaScript (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.pngJavaScript (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
| Status | Meaning |
|---|---|
| 401 | Missing or invalid API token — sign in and copy your token from the editor |
| 400 | Missing or invalid parameters (e.g. no url, unsupported format) |
| 403 | Request origin not allowed (CORS) |
| 429 | Rate 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. |
| 502 | Source image could not be fetched from the given URL |
| 500 | Image 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
qparameter is ignored. - →The
bghex 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
Authorizationheader 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