Référence API
Quick Start
CloudPhoto resizes, transforms, compresses & optimizes your images on-demand from a single URL. The v2 API uses query parameters for maximum flexibility — works from any language, no SDK required.
https://cdn.cloudphoto.io/<token>/img?<params>&sig=<signature>&url=<source_image_url>
Golden rule —urlis always the LAST parameter. Everything afterurl=is the source image URL, including its own query string (e.g. Centrismedia.ashx?id=...&t=pi). All CloudPhoto parameters come beforeurl=. The source URL is taken raw — no encoding needed.Parameter names. Each parameter has a long, canonical form (used throughout this doc) and a short alias — both are accepted:width/w,height/h,format/f,quality/q,aspect_ratio/ar,gravity/g,filters/fx,metadata/md.Signing is required. Every v2 request must carry a validsig— an HMAC keyed by your token's secret. The examples below include a real one so you can see exactly where it goes; full recipe under Signing your URLs. (Thedemotoken is technically exempt, but the examples sign anyway.)
Example — resize to 600px wide, served in the best format the browser accepts (the
sig is computed from the token's secret):https://cdn.cloudphoto.io/demo/img?width=600&sig=hoxDw18eiRCB_oyTPvVTSg&url=https://samples-photos.com/tennis.jpg
The default is
auto: each browser gets the best format it accepts — AVIF if supported, then WebP, falling back to the source format. Pass an explicit &format=webp (or jpg/png) for a single fixed format across all clients, or &format=original to keep the source format.Production URLs go through the CDNcdn.cloudphoto.io(cached, fast). The examples below hit the originapp.cloudphoto.iodirectly — both expose the same API.
Parameters
| Parameter (alias) | Description |
|---|---|
token |
Your CloudPhoto customer token (first path segment). |
width (w) |
Target width in pixels. Alone, keeps the aspect ratio. |
height (h) |
Target height in pixels. Alone, keeps the aspect ratio. |
fit |
Resize operation (see Operations). Omitted → derived from the dimensions. |
aspect_ratio (ar) |
Target aspect ratio (16:9 or 1.5). With a single dimension, derives the other and crops to the ratio. |
dpr |
Device pixel ratio (1–5) for retina. Multiplies the requested dimensions. |
format (f) |
Output format: auto (default, negotiated via Accept), or force webp/avif/jpg/png/original. |
quality (q) |
Quality 1–100, or auto. Defaults tuned per format. |
gravity (g) |
Focus region for crop (see Filters → gravity), including entropy (content-aware smart crop, no AI). |
filters (fx) |
Dot-separated chain of filters (see Filters), e.g. brightness120.saturation140.blur3. |
org_if_sml |
1 = never upscale: if the source is smaller than the target, serve it at its own size. |
metadata (md) |
1 = keep image metadata (EXIF/IPTC). Stripped by default for lighter files. |
ci_info |
1 = return transformation metadata as JSON (format, dimensions, weight, cache, timings) instead of the image. |
force |
1 = bypass cache and regenerate. |
sig |
HMAC signature of the request — required on every token except demo (see Signing your URLs). Goes right before url=. |
url |
The source image URL. Always last, taken raw. |
Signing your URLs
Every v2 request must be signed — except the public
demo token used in the examples above. An unsigned or tampered request on your token returns a placeholder image with a 403. This stops anyone who sees one of your URLs from reusing your token to generate unlimited new variants (each new variant costs a download, image processing, storage and bandwidth).Each token has a secret (in your CloudPhoto dashboard). You compute an HMAC-SHA256 over the request, keyed by that secret, keep the first 16 bytes and base64url-encode them (no padding) → a 22-character
sig, placed right before url=.The signed message is all your parameters except
sig, then url=<source> — the exact bytes you put in the URL (no re-encoding):message = "width=600&filters=sharpen10" + "&" + "url=https://example.com/photo.jpg" sig = base64url( HMAC_SHA256(secret, message)[0..15] )
Ruby:
require "openssl" require "base64" secret = "<your token secret>" # from the dashboard — keep it server-side before = "width=600&filters=sharpen10" # your parameters, WITHOUT sig source = "https://example.com/photo.jpg" message = [before.presence, "url=#{source}"].compact.join("&") sig = Base64.urlsafe_encode64(OpenSSL::HMAC.digest("SHA256", secret, message)[0, 16], :padding => false) url = "https://cdn.cloudphoto.io/<token>/img?#{before}&sig=#{sig}&url=#{source}"
Sign on your backend, never in browser JavaScript. HMAC is symmetric — anyone with the secret can sign (and forge). Build signed URLs server-side, or expose a small signing endpoint; never ship the secret in a JS bundle.No expiry, cache-friendly. Signed URLs don't expire — they cache for a month like any other. To revoke access, rotate the token's secret.format=auto. Sign your URL exactly as written (or omitformat—autois the default). Format negotiation happens server-side and the image is served directly on the same URL — no redirect, your signature is never touched.
Operations
The
fit parameter selects the resize behavior. When omitted: width+height → crop, a single dimension → width/height.| Operation | Description |
|---|---|
none |
No resize — only re-encode / apply filters. |
width |
Resize to a width, height proportional. |
height |
Resize to a height, width proportional. |
crop |
Fill the exact widthxheight box and crop the overflow (use gravity to choose the region). |
cover |
Force the exact widthxheight, ignoring the ratio (may distort). |
fit |
Fit entirely inside widthxheight (letterbox), padded with the color filter (transparent for PNG). |
bound |
Fit inside widthxheight keeping the ratio, without padding (output may be smaller). |
Filters
Filters go in the
filters parameter (alias fx), separated by dots: filters=contrast20.colorFF0000.colorize30. The value is appended to the name without a separator, so values never contain a dot — gamma120 means gamma 1.2, opacity50 means 50%. Gravity has its own gravity parameter.Geometry
| Filter | Description |
|---|---|
rot<deg> |
Rotate by <deg> degrees. The empty area uses the color filter. |
flip |
Mirror vertically. |
flop |
Mirror horizontally. |
trim<fuzz> |
Remove uniform borders (<fuzz>% tolerance, default 5). |
border<n> |
Add an <n>px border in the color filter color. |
Color
| Filter | Description |
|---|---|
color<HEX> |
Color used by fit padding, colorize, border and rot (e.g. colorFF0000, colortransparent). |
colorize<0-100> |
Overlay the color tint at the given opacity. |
colorspace<X> |
Output colorspace: sRGB, RGB, Gray. |
grayscale |
Convert to grayscale. |
sepia<n> |
Sepia tone (default 80%). |
negate |
Invert the colors (negative). |
gamma<n> |
Gamma correction, <n>÷100 (gamma120 = 1.2). |
brightness<n> |
Brightness, 100 = neutral (0–200). |
saturation<n> |
Saturation, 100 = neutral. |
hue<n> |
Hue rotation, 100 = neutral. |
contrast<0-100> |
Increase contrast. |
threshold<n> |
Black & white at the <n>% threshold. |
autocontrast |
Auto-stretch the tonal range. |
opacity<0-100> |
Global opacity (needs an alpha-capable output: PNG/WebP). |
Effects
| Filter | Description |
|---|---|
blur<n> |
Gaussian blur. |
sharpen<n> |
Sharpen (unsharp mask). |
pixelate<n> |
Pixelate in blocks. |
oilpaint<n> |
Oil-paint effect (<n> radius). |
vignette<n> |
Dark vignette (<n> spread). |
Gravity (
gravity parameter, alias g) — used by crop: Center, North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest, and entropy (content-aware smart crop, no AI — picks the most detailed region).Responsive images
Use
dpr for retina, and a plain HTML srcset with several widths — just vary the width parameter (no SDK, any framework):<img src="https://cdn.cloudphoto.io/demo/img?width=800&format=auto&url=https://example.com/photo.jpg" srcset="https://cdn.cloudphoto.io/demo/img?width=400&format=auto&url=https://example.com/photo.jpg 400w, https://cdn.cloudphoto.io/demo/img?width=800&format=auto&url=https://example.com/photo.jpg 800w, https://cdn.cloudphoto.io/demo/img?width=1200&format=auto&url=https://example.com/photo.jpg 1200w" sizes="(max-width: 600px) 100vw, 800px" alt="Property photo">
format=auto lets the browser get AVIF/WebP automatically; each width is a separate cached variant.Examples
width=600 — resize, best format auto-negotiated
600×450
(63,2 ko)
-82%
format=avif — next-gen format, lighter
600×450
(30,2 ko)
-91%
crop 700x300 + gravity=entropy — smart crop (content-aware, no AI)
700×300
(69,2 ko)
-80%
crop 700x300 + gravity=East — manual focus
700×300
(60 ko)
-83%
aspect_ratio=16:9 + dpr=2 — ratio + retina
1000×562
(136 ko)
-61%
filters=grayscale
600×450
(53,6 ko)
-85%
filters=sepia
600×450
(68,2 ko)
-81%
filters=negate — invert colors
600×450
(63,2 ko)
-82%
filters=brightness130.saturation150 — color adjust
600×450
(74,1 ko)
-79%
filters=gamma60 — gamma correction (0.6)
600×450
(60,5 ko)
-83%
filters=contrast30.color3366FF.colorize25 — tint
600×450
(53,4 ko)
-85%
filters=blur8
600×450
(12,7 ko)
-96%
filters=sharpen3
600×450
(84,9 ko)
-76%
filters=pixelate12
600×444
(14,2 ko)
-96%
filters=vignette40
600×450
(44,2 ko)
-87%
filters=oilpaint3 — oil-paint effect
600×450
(55,7 ko)
-84%
filters=threshold55 — black & white
600×450
(52,5 ko)
-85%
filters=rot8 — rotate 8° (background color)
550×443
(43,8 ko)
-87%
filters=flop — horizontal mirror
600×450
(63,1 ko)
-82%
filters=border24 + colorFFFFFF — solid border
648×498
(65,1 ko)
-81%
Combo: crop + entropy + sepia + border
532×532
(66 ko)
-81%