Skip to content

URL API

Deterministic, human-readable URLs for transformed image delivery.

Every image is served from a deterministic, human-readable URL. Add a transform segment to the path to resize, crop, and re-format on the fly — the edge transforms once and caches forever.

URL structure

https://cdn.auraimage.ai/[projectName]/[transform]/[name][.ext]
SegmentDescriptionExample
projectNameYour project identifier — same as NEXT_PUBLIC_AURA_PROJECT_NAME.my-app
transformOptional comma-separated transform options — one path segment, right after the project.w=800,q=75
nameThe extension-less name returned by upload (or whatever you stored).abc123xyz0-hero
.extOptional format extension. Omit it for automatic format selection (recommended)..avif
https://cdn.auraimage.ai/my-app/w=800,q=75/abc123xyz0-hero

The transform segment is optional — https://cdn.auraimage.ai/my-app/abc123xyz0-hero serves the full-size image with automatic format negotiation.

Transform options

Transform options are a single comma-separated path segment placed immediately after the project name — w=1920,fit=face,q=75. Recognized keys are w, h, fit, and q (plus lqip, below). The grammar is strict: an unknown key, a duplicate key, or an invalid value returns 400 naming the offender — options are never silently ignored.

Sizing

OptionTypeDefaultNotes
wintegerWidth in pixels. Capped at 4096. Height scales proportionally unless h is also set.
hintegerHeight in pixels. Capped at 4096.
fitstringcoverHow to fit the image into the requested box. Only meaningful when w or h is set.

Nearby w / h values may be coalesced onto a shared variant to keep the edge cache economical — standardize on a small set of widths and you'll hit cache more often.

fit values:

ValueBehavior
coverCrop to fill the exact box.
containLetterbox — full image visible, no crop.
faceCloudflare-native face detection. Crops the most prominent face into the box.
autoCloudflare-native saliency detection. Crops to the most visually important region.

When fit=face or fit=auto succeeds, the response carries X-Aura-Smart-Crop: ok. When no face / salient region is detected, the result falls back to a centered cover crop (the header is omitted).

Quality

OptionTypeDefaultNotes
q1–10080Compression quality. Ignored for lossless masters served pass-through.

Format

Output format is chosen by the URL's trailing extension — there is no fmt option.

ExtensionBehavior
(none)Recommended. Automatic — picks the best format the client accepts (AVIF → WebP → JPEG). The extension-less URL is canonical.
.avifForce AVIF.
.webpForce WebP.
.jpg / .jpegForce JPEG.
.pngForce PNG.

Because the extension-less URL negotiates the best modern format automatically, prefer it for <img> tags. Pin an explicit extension only when the consumer can't send an Accept header — most importantly og:image, where you should use an explicit .jpg or .png.

Requesting a known-but-non-servable extension (.gif, .heic, .tiff, .bmp) returns 400 with guidance: request /{name} for automatic format, or one of .jpg, .png, .webp, .avif.

Loading helpers

OptionTypeDescription
lqipflaglqip=true returns a low-quality image preview (small, heavily compressed) for placeholder rendering — e.g. /my-app/lqip=true/abc123xyz0-hero.

For a BlurHash placeholder, fetch it as JSON from GET /v1/blurhash/<projectName>/<name>{ "blurhash": "..." }. The <AuraImage /> component uses this internally.

Build URLs from code

Rather than concatenating the path yourself, the @auraimage/sdk package ships two helpers that serialize these URLs for you — handy when you set an image src manually instead of using the <AuraImage /> component. Both are pure and browser-safe (they take no secret key and make no network calls), and both build public URLs — for a private image, sign one with getSignedUrl instead.

buildServeUrl takes friendly parameter names and emits the transform segment, format extension, and cache-buster in the correct grammar:

import { buildServeUrl } from '@auraimage/sdk';

buildServeUrl({
  cdnUrl: 'https://cdn.auraimage.ai',
  project: 'my-app',
  name: 'blog/hero', // the extension-less name returned by upload
  width: 800,
  height: 600,
  quality: 75,
  format: 'auto', // 'auto' | 'jpeg' | 'png' | 'webp' | 'avif'
  v: 3 // optional cache-buster
});
// → https://cdn.auraimage.ai/my-app/w=800,h=600,q=75/blog/hero?v=3

Only cdnUrl, project, and name are required. The rest map to the grammar above — width→w, height→h, fit→fit, quality→q, lqip→lqip=true, and format to the trailing extension — and any option you omit is left out of the URL. width/height (positive integers) and quality (1–100) are validated: a bad value throws instead of producing a URL the CDN would reject.

buildBlurhashUrl builds the placeholder-metadata URL from Loading helpers:

import { buildBlurhashUrl } from '@auraimage/sdk';

const url = buildBlurhashUrl({ cdnUrl: 'https://cdn.auraimage.ai', project: 'my-app', name: 'blog/hero' });
// → https://cdn.auraimage.ai/v1/blurhash/my-app/blog/hero

const { blurhash, width, height } = await fetch(url).then((r) => r.json());

Content negotiation

When the URL has no extension (automatic format), the edge reads the Accept header and serves in priority order:

AVIF  →  WebP  →  JPEG

The response carries Vary: Accept so the cache stores one variant per accept-class — no cross-browser cache poisoning.

Query parameters

Only two query parameters are honored:

ParamPurpose
vCache-buster. Bump it to force a fresh variant after an overwrite.
tokenServe token for private images.

Transform options must live in the path segment. A legacy transform query param (?w=800, ?fmt=auto, ?blur=true, …) returns 400 — a tripwire so a half-migrated URL fails loudly instead of silently serving a full-size original. All other query params (utm_*, fbclid, …) are ignored, so link decoration never breaks an image or fragments the cache.

SEO names

Descriptive names improve image rankings in Google Images. An image's name is its extension-less identity — set a meaningful one at upload time (via the upload token's name claim, or let it be auto-generated from a descriptive uploaded file name):

# Good — descriptive
https://cdn.auraimage.ai/my-app/abc123xyz0-golden-gate-bridge-sunset

# Avoid — opaque
https://cdn.auraimage.ai/my-app/abc123xyz0-img-00432

Use hyphens as separators. Names may contain / to group images into path segments (e.g. blog/hero).

Project names are immutable

A project name is permanent. Renaming would break every published URL, so the dashboard does not allow it. Pick carefully during aura init or MCP install.

Reserved names (cannot be used as a project name): api, admin, cdn, health, registry, static, test, v1.

Caching behavior

VisibilityCache-ControlEdge cache
Publicpublic, max-age=31536000, immutableYes — first request transforms, every subsequent request hits the edge.
Private (?token=)private, max-age=300No — every request bypasses the shared edge cache and hits origin.

Cache tags are set on every public response so you can purge surgically:

TagApplies to
project-<projectName>Every public image in the project.
fit-facePublic images served with fit=face.
fit-autoPublic images served with fit=auto.

Purge a single project from the dashboard without affecting any other project, and re-render smart-cropped variants without invalidating exact-size crops.

Response headers

Every successful image response carries:

HeaderValuesMeaning
X-Aura-CacheHIT | MISSWhether the edge cache served this response.
X-Aura-Smart-CropokSet only when fit=face / fit=auto produced a crop. Absent on fallback.
Server-Timingsee belowPer-stage timings, set on both hits and misses.
VaryAcceptRequired for correct format negotiation caching.

Server-Timing

A standard Server-Timing header lets you measure delivery in DevTools or RUM without any custom instrumentation.

On a cache hit:

Server-Timing: cache;desc="HIT";dur=<ms>

On a cache miss:

Server-Timing: cache;desc="MISS";dur=<ms>, r2;dur=<ms>, process;desc="transformed";dur=<ms>

Pass-through misses (no transformation needed) report process;desc="passthrough";dur=0.

StageWhat it measures
cacheEdge cache lookup.
r2Origin object fetch from R2.
processTransformation (resize, format conversion, smart crop). passthrough when the master is served as-is.

Open Chrome DevTools → Network → click any image response → Timing tab to see these stages plotted alongside browser timings.