web

Placeholder photos at any size

https://hypothesis.sh/photo/600/400 returns a 600×400 photo. Dimensions go in the path, an image comes back. No account, no key, no request body.

/photo/200                   random square photo, 200×200
/photo/600/400               random photo at 600×400
/photo/seed/hero/1200/630    the same photo for "hero", every time
/photo/id/7/400              photo 7 from the library

Sizes run from 1 to 1600 on either axis. The explorer at /photo builds these URLs from controls and previews them live, and the docs cover every form.

Seeds make URLs safe to hardcode

A seeded URL resolves to the same source photo at any size, in any format, with any filter. Snapshot tests and design fixtures can hardcode it without the layout shuffling between runs.

Unseeded requests pick a photo at random and answer with a 302 to that photo's /photo/id/{n}/… URL. If you want to keep the photo you got, keep the URL you were redirected to.

Filters and formats

?grayscale desaturates. ?blur=1 through ?blur=10 applies a gaussian blur, and the two combine. JPEG is the default; append .webp to the size for WebP:

/photo/600/400?grayscale
/photo/seed/hero/1200/630?grayscale&blur=3
/photo/600/400.webp

Built for hotlinking

Every response carries Access-Control-Allow-Origin: * and long-lived cache headers, so the images work in img tags, CSS backgrounds, canvas, and cross-origin fetch(). A Photo-ID response header names the photo a response came from, and it's readable from cross-origin JavaScript.

Where the images come from

The library is AI-generated photography: landscapes, architecture, food, textures. There are no model or property releases to worry about, and nothing in it belongs in production content. Source images are 512×512, so large renders are upscales; a 1600px hero will look soft next to real photography, which is the reason sizes stop there.