Assets and images
Every image and file in a Content Delivery API response has an absolute, permanent URL that browsers and CDNs may cache for a year. Images can be resized and converted on request with w, h, fit, fmt and q. This page is for developers who show Spatibase images and files on a website or in an app.
What does an asset URL look like?
An asset URL has the form https://api.spatibase.com/assets/<assetId>/<filename>. Assets appear in images and files fields (Field values) as objects like this:
{"id": "b8251bf8-2fab-4001-a3a1-49465ebcabfb", "url": "https://api.spatibase.com/assets/b8251bf8-2fab-4001-a3a1-49465ebcabfb/redwood-national-park-1.jpg", "filename": "redwood-national-park-1.jpg", "mimeType": "image/jpeg", "size": 31475, "width": 1600, "height": 1000, "alt": "Redwood National Park, trailhead view"}
- The file route is outside
/delivery/v1and not scoped to a project. The asset is found by its id; the filename part is cosmetic, so/assets/<id>or any other name returns the same file. urlis always absolute. Links to the project’s files insidemarkdownfields are rewritten to the same absolute form.- A file’s content never changes under its id. Editing the alt text or the filename changes the JSON, not the bytes, and old URLs with the previous filename keep working. Deleting an asset makes its URL return
404and removes it from fields. A deleted asset stays in the trash for 30 days: restoring it brings its URL back, and once it is deleted for good the URL stays404.
The asset URL and its parameters are also described in both OpenAPI files (getAssetFile).
Are asset URLs public?
Yes. Asset URLs work without an API key, also in private projects, because an <img> tag cannot send one. Anyone with the URL can download the file, whether or not an entry using it is published; an uploaded file that is used nowhere is still served. Asset ids are long random UUIDs, but Spatibase does not sign file URLs, so do not upload anything private.
Which files count as images?
Spatibase treats a file as an image when its content is JPEG, PNG, GIF, WebP, AVIF or SVG, whatever its extension. Only images accept the resize and format parameters.
| Images | Other files | |
|---|---|---|
| Detected by | file content: JPEG, PNG, GIF, WebP, AVIF, SVG | everything else, including TIFF and HEIC |
mimeType |
image/jpeg, image/png, image/gif, image/webp, image/avif, image/svg+xml |
from the upload, else from the extension, else application/octet-stream |
width, height |
displayed size in pixels (EXIF rotation applied; first frame for animations) | null |
| Resize parameters | applied | ignored, even invalid ones: trail-map.pdf?w=200&fmt=webp returns the PDF |
Each uploaded file can be at most 25 MB (Limits).
How do I resize or convert an image?
Add query parameters to the image URL. This returns an 800 px wide WebP version:
https://api.spatibase.com/assets/b8251bf8-2fab-4001-a3a1-49465ebcabfb/redwood-national-park-1.jpg?w=800&fmt=webp
| Parameter | Values | Default | Meaning |
|---|---|---|---|
w |
1 to 4000 | none | target width in pixels, rounded up to the size ladder |
h |
1 to 4000 | none | target height in pixels, rounded up to the size ladder |
fit |
cover, contain, inside |
cover with both w and h, otherwise inside |
cover: crop to fill the box; contain: fit inside and pad to the box; inside: fit inside, no padding |
fmt |
webp, jpeg (or jpg), png, avif |
the source format | output format |
q |
1 to 100 | 80 | quality for webp, jpeg and avif, rounded to the nearest 10 (at least 10); ignored for png and gif |
Values are case-insensitive (fmt=WEBP works). Each parameter may appear once. Out-of-range or unknown values on an image are a 400:
{"error":{"code":"bad_request","message":"\"fmt\" must be one of webp, jpeg, png, avif (got \"gif\")"}}
Size ladder
w and h snap up to the next of these sizes: 16, 32, 48, 64, 96, 128, 160, 200, 256, 320, 400, 480, 512, 640, 800, 960, 1024, 1280, 1600, 1920, 2048, 2560, 3200, 3840. Values above 3840 become 3840. Then:
- Raster images are never enlarged: the result is at most the original size.
- With only
wor onlyh, the other side follows the aspect ratio. - With both, and
coverorcontain, the box keeps its shape and shrinks until it fits the original. wandhsnap independently, sow=400&h=300becomes a 400×320 box.
Results for a 1600×1000 JPEG:
| Query | Output |
|---|---|
?w=400 |
400×250 |
?w=401 |
480×300 |
?h=100 |
205×128 |
?w=3000 |
1600×1000 (not enlarged) |
?w=400&h=300 |
400×320, cropped (cover) |
?w=400&h=300&fit=contain |
400×320, padded |
?w=400&h=300&fit=inside |
400×250 |
?w=500&h=500 |
512×512, cropped |
?w=1000&h=1000&fit=inside |
1024×640 |
?w=4000&h=4000 |
1000×1000 (a 3840×3840 box shrunk to fit) |
?fmt=webp |
1600×1000 WebP |
Formats
- Without
fmt, the output keeps the source format. Animated GIF and WebP stay animated when the output is GIF or WebP;fmt=png,jpegoravifkeeps only the first frame. fmt=jpegflattens transparency onto white.containpadding is white for JPEG and transparent for PNG, WebP and AVIF.- SVG is served unchanged unless
fmtis given:logo.svg?w=400returns the original SVG. Withfmt, it is rasterised at the requested size and may be larger than its nominal size:logo.svg?w=400&fmt=pngof a 64×32 SVG gives 400×200. - No new image is made when nothing would change:
fitalone, or a PNG or GIF requested in its own format or with onlyq, returns the original. A JPEG, WebP or AVIF with onlyq, or with its ownfmt, is re-encoded at that quality. - Because
qis rounded,q=55andq=64produce the same file;q=66makes a new one.
How do I serve responsive images?
Use srcset with widths taken from the size ladder, so every URL maps to one cached variant, and the asset’s width, height and alt for layout and accessibility:
<img
src="https://api.spatibase.com/assets/b8251bf8-2fab-4001-a3a1-49465ebcabfb/redwood-national-park-1.jpg?w=640&fmt=webp"
srcset="https://api.spatibase.com/assets/b8251bf8-2fab-4001-a3a1-49465ebcabfb/redwood-national-park-1.jpg?w=320&fmt=webp 320w,
https://api.spatibase.com/assets/b8251bf8-2fab-4001-a3a1-49465ebcabfb/redwood-national-park-1.jpg?w=640&fmt=webp 640w,
https://api.spatibase.com/assets/b8251bf8-2fab-4001-a3a1-49465ebcabfb/redwood-national-park-1.jpg?w=1280&fmt=webp 1280w"
sizes="(max-width: 700px) 100vw, 640px"
width="1600" height="1000"
alt="Redwood National Park, trailhead view">
Above the original width (here 1600 px) every request maps to the same 1600 px variant. A JavaScript version that builds this from an images field is in Recipes.
Which caching headers do assets send?
Originals and resized variants are cached for a year as immutable, because the content never changes under an asset id.
| Header | Value |
|---|---|
Cache-Control |
public, max-age=31536000, immutable on originals and variants |
ETag, Last-Modified |
ETag always, Last-Modified on originals and cached variants; If-None-Match returns 304 |
X-Variant-Cache |
MISS (rendered for this request) or HIT (served from the variant cache); absent for originals |
Content-Type |
the asset’s mimeType, or the output format |
Content-Disposition |
inline with the filename, its extension changed to the output format (redwood-national-park-1.webp; .jpg for JPEG) |
Access-Control-Allow-Origin |
*; OPTIONS allows Range and If-None-Match |
X-Content-Type-Options |
nosniff |
Content-Security-Policy |
default-src 'none'; img-src data:; style-src 'unsafe-inline'; sandbox for SVG, HTML, XML and JavaScript files, so an uploaded file cannot run script when opened directly |
- Originals support
Rangerequests (206 Partial Content), useful for large downloads and video. - The first request for a new variant renders it, which is slower; later requests are served from the variant cache. The variant cache has a size limit: when it is full, the oldest variants are removed and rendered again when next requested.
- The first response for a new variant can have a different
ETagfrom later responses for the same URL, so one revalidation may return200instead of304. With year-long immutable caching this rarely matters. - Files are served through Spatibase’s CDN; year-long caching is safe because content never changes under an id. A deleted file can still be served from the CDN until its cached copy expires.
Asset errors
Asset errors use the same JSON format as the Content Delivery API, with Cache-Control: no-store:
| Status | code |
When |
|---|---|---|
| 400 | bad_request |
invalid w, h, q, fit or fmt on an image, or a parameter given twice |
| 404 | not_found |
unknown or malformed asset id (Asset "<id>" not found), the file is missing, or the path is not /assets/<id> or /assets/<id>/<filename> |
| 405 | method_not_allowed |
any method other than GET, HEAD or OPTIONS |
Related
Updated