Blazing fast,
on-demand images.

Crabcrop is a Rust-built, lightning-fast on-demand image API supporting all major formats in and out, with over 42 filters and AI features like background removal. It resizes, crops, converts, and filters your images straight from a signed URL. One binary, no pre-generated thumbnails, no build step.

Install

Running in a minute.

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/dayvson/crabcrop/releases/latest/download/crabcrop-installer.sh | sh
Other routes: AI image · Release binaries · cargo install crabcrop
Major features

Everything an image pipeline does, in one signed URL.

Snap the crab as a stage magician

Supported formats

JPEG, PNG, WebP, GIF, AVIF, and JPEG XL, in and out. HEIC and HEIF decode only; SVG decodes, sanitized and rasterized. Name no format and the visitor's Accept header decides: AVIF first, then JPEG XL, then WebP. An explicit format(...) always wins. Sources are not just stills: frame: picks one frame of a video and page: picks one page of a PDF, and either becomes the image the URL works on.

format(avif) · format(jxl) · format(webp) · frame:50% · page:2
Snap waving while holding a photo print

More than photos

The source can be one frame of a video, one page of a PDF, an object in S3 or GCS, a local file, or a short root: reference the server expands against its own origins. Originals can also arrive through the signed upload endpoint, off by default.

frame:50% · page:2 · root:photos/cat.jpg · PUT /upload/<name>
Snap flipping photo prints on a grill

45 filters, one chain

Resize, crop, fit-in, and pad are their own path segments. The 45 filters chain inside one filters: segment, everything running in the order written.

filters:sharpen(1.2):saturation(1.1)
Snap with the background removed, over transparency

Background removal

Your ONNX model, in process. The subject stays, the background becomes real alpha.

filters:removebg:format(webp)
Snap composited onto a tide green brand backdrop

Studio mode

The listing shot in one filter: cut out, backdrop, contact shadow, margin. Backdrops resolve on the server, brand color included. Or keep the photo: studio(scene) reframes on the subject and corrects the light and color.

filters:studio(product,bg:brand) · filters:studio(scene)
Smart crop keeping the whole crab in frame

Smart crop, face safe

The crop window finds the subject, and keeps detected faces whole instead of clipping them at the edge.

crop:760x760:smart
A background skater blurred by class redaction

Redaction

Blur or pixelate faces, or every detected object of a class. Redaction never guesses: a detection failure fails the request. With a segmentation model configured, class redaction follows the object's silhouette instead of its box, and recolorclass paints that silhouette a solid color.

filters:blurclass(person) · filters:recolorclass(car,ff0000)
Snap beside a grill on the beach at sunset

Object removal

Name a rectangle and a LaMa family inpainting model fills it in from the surrounding pixels. Everything outside the rectangle comes back bit-identical.

filters:remove_region(40,120,300,200)
Snap in a tight square crop

AI upscale

Super-resolution from a model you supply: upscale(2) or upscale(4) rebuilds detail instead of stretching pixels, and source transparency carries across. It never falls back to a plain resize.

filters:upscale(2)
Snap at the edge of a skate bowl with a skater riding in the background

Face detection

A YuNet model finds the faces in the frame. Smart crops center on them and keep them whole, :face crops to the largest face, and blurfaces or pixelatefaces redact every face found.

crop:760x760:face · filters:blurfaces
Snap stamping a wax seal onto a scroll

Presets and purge

Server-side preset names keep templates short. Purge one result, or a whole preset group, with signatures from their own subkey.

preset:og-card · POST /purge-group
Snap holding a photo tucked inside an envelope closed with a wax seal

Sealed URLs

For links that stay public but unreadable: the whole recipe, operations and source together, encrypted into one opaque token in the signature slot. Only the server opens it, and the sealed spelling serves the same render as the readable one.

s1.<token>/photo.jpg
Snap scanning a photo with a magnifying glass

Meta that describes

Ask for JSON and get dimensions, format, byte size, and provenance for every render. The richer answers are separate opt-ins, each with its own model set: CLIP tags and alt text, detections, moderation verdicts, embeddings, an aesthetic score, and OCR text.

Accept: application/json; detections=1
A surfer scene at the beach

Text out of the picture

Opt a meta request in and the answer reads the picture: the text lines in reading order, each with its box and a confidence score, from a PP-OCR model pair you supply. The annotation never touches the image bytes.

Accept: application/json; ocr=1
Snap on the beach beside a film camera on a tripod

Provenance: C2PA

Meta reports the Content Credentials a source carries: whether a manifest is present, whether it validates, and who signed it. Configure your own certificate and still JPEG, PNG, WebP, and AVIF outputs are signed as they are served, with the source recorded as an ingredient, so the chain survives the transform.

CRABCROP_C2PA_CERT · CRABCROP_C2PA_KEY
Snap clicking colored blocks into a row at a workbench

URLs that explain themselves

Put explain/ in front of any signed URL and the server reports on it instead of serving the image.

GET /explain/<signature>/...
Snap peeking over a picture, half sketch and half finished color

SDKs and loaders

Build and sign these URLs from code instead of by hand: SDKs for TypeScript and Python, the crabcrop-url Rust crate, an MCP server that lets coding agents sign, explain, and inspect URLs, and loaders for Next.js, Nuxt, and Hydrogen.

@crabcrop/url · crabcrop_url · crabcrop-url · @crabcrop/mcp
Signing

Sign a URL, from any stack.

Every URL carries an HMAC-SHA256 signature over the operations and the source, lowercase hex. Sign with the TypeScript or Python SDK, the crabcrop-url Rust crate, or plain curl: same inputs, same URL.

printf '%s' 'crop:1200x630:smart/filters:format(webp):quality(80)/https://example.com/photo.jpg' \
  | openssl dgst -sha256 -hmac 'demo-secret'
# SHA2-256(stdin)= ca3d1f22f4cc3860926608df02383f46dcf74af9a4e1bc26b1a00c644f55f300
import { buildURL } from "@crabcrop/url";

const url = buildURL({
  base: "https://img.example.com",
  secret: "demo-secret",
  operations: "crop:1200x630:smart/filters:format(webp):quality(80)",
  source: "https://example.com/photo.jpg",
});
from crabcrop_url import build_url

url = build_url(
    base="https://img.example.com",
    secret="demo-secret",
    operations="crop:1200x630:smart/filters:format(webp):quality(80)",
    source="https://example.com/photo.jpg",
)
use crabcrop_url::{build_url, sign};

let signature = sign(secret, "crop:1200x630:smart/filters:format(webp):quality(80)/https://example.com/photo.jpg");
let url = build_url(base, secret,
    "crop:1200x630:smart/filters:format(webp):quality(80)",
    "https://example.com/photo.jpg")?;

Each snippet signs the same example with the sample secret demo-secret. Swap in your base, your secret, and your operations.

The source can be a short root reference instead of a full URL, like root:photos/cat.jpg: the server expands it against an origin configured on the server, so the origin itself never appears in the URL.

A URL can also be sealed: the whole recipe, operations and source, encrypted into one opaque token in the signature slot, for links that have to stay public but unreadable. The readable form stays the default. See sealed URLs in the docs.

Studio mode

Studio product shots, in one URL.

studio(product) cuts the subject out of a photo taken anywhere and composites it onto a clean backdrop (white, a hex color, or your brand color) over a soft contact shadow: a finished product shot, in one URL. The skate park photo below is a real output from a running server. Drag the slider.

Snap composited by studio mode onto a white backdrop with a soft contact shadow
Snap the crochet crab at a skate park, original photo
studio(product)BEFORE

fit-in:1000x667/filters:studio(product,bg:white,shadow:soft,pad:10)

AI features

Models you supply. Inference in process.

Real outputs from a running server, nothing retouched. No model configured means a clean 501, never a silent fallback.

Snap at the skate park with the background removed, over transparency
Snap the crochet crab at a skate park, original photo
AFTERBEFORE

Background removal

fit-in:1000x667/filters:removebg:format(webp)

The skate park photo with the skateboard pixelated by crabcrop
Snap at the skate park next to a skateboard, original photo
AFTERBEFORE

Redact a class: pixelate

fit-in:1100x733/filters:pixelateclass(skateboard)

Plus upscale, region removal by inpainting, face redaction, smart crops, and the meta family: AI in the documentation.

The full documentation.

Every operation with examples and interactive demos, section by section.

Read the documentation