Overview — Dynamic Images
A dynamic image is a public URL that renders a static design on the fly. You create the base URL once with an API call; after that, every variant is just a query string — no API key, no generation request, no SDK. Embed it in an <img> tag, an email, a CMS, or a chat message, and the image personalizes itself at display time.
https://img.abyssale.com/{dynamicImageId}/{format}?title=Hello%20Alice
Static designs only
Dynamic images work on static designs. Animated, print and multi-page designs cannot be minted into a dynamic image (400 template_not_static).
How it works
POST /designs/{designId}/dynamic-image-urlOne authenticated call mints the design's dynamic image and returns one URL per format. One dynamic image per design — calling again returns the same URL.
?layer.property=valueAppend element overrides to the URL — text payloads, colors, image sources, visibility — using the same layer names and properties as the Generation API.
<img src="…">The URL serves the rendered image directly (correct Content-Type, CORS open). Each unique variant renders once, then is served from cache.
Test mode vs production mode
A dynamic image is created in test mode by default; enable production mode in the creation call.
| Test mode (default) | Production mode | |
|---|---|---|
| Rendered variants | Saved and visible in your Abyssale workspace, and editable there | No record is kept — the variant never appears in the workspace and cannot be opened in the editor |
| Per-image rate limit | 10 requests/s per dynamic image | No per-image request-rate limit |
NEW_BANNER webhook | Fires for each rendered variant | Does not fire, and no thumbnail is produced |
| Settings changes | Take effect immediately | Take up to 10 seconds to propagate |
In production mode there is no per-image request ceiling, so it absorbs traffic peaks — an email campaign where thousands of opens hit the URL at once. It is not unlimited: your generation credits and your plan's bandwidth still apply, and so does enable_rate_limit if you set it.
Production variants leave no trace
Nothing is stored, so there is no thumbnail, no editable copy, and no NEW_BANNER delivery to key a workflow off. If you need a record of what was rendered, keep it on your side — the URL that produced it is the only handle you have. The 10-second propagation delay applies to the same settings the creation call sets, so deactivating a public URL is not instant.
Enable enable_rate_limit on any URL exposed to an untrusted audience. Independently of the mode, it caps one viewer at 5 generations per 24 h, which is what stops someone scripting your public URL. Only requests that actually render count — anything served from cache is returned without touching the limit. The viewer is identified by a hash of their IP address and User-Agent, so the cap follows the person, not the variant.
Security model
- The URL carries no API key and no signature — anyone holding it can render variants. Its only protection is the unguessable random
dynamicImageId. - Renders are gated server-side: your plan must include the Dynamic Images feature (otherwise the URL answers
401), your credit balance is checked (429when exhausted), and a deactivated dynamic image stops rendering (400). - Responses set
Access-Control-Allow-Origin: *, so variants can be fetched from any origin.
Credits, caching and bandwidth
- 1 generation credit per render — the first request for a given query string renders the image and consumes one credit. Requests answered from cache render nothing and cost no credit. Dynamic images spend the same balance as every other generated asset; there is no separate currency for them.
- Rendered variants are cached at the CDN, so a variant that stays warm is served without re-rendering. A request that misses the cache is rendered again, and billed again.
- Saving the design refreshes every variant. Each save queues a CDN invalidation covering every variant of that dynamic image, so viewers pick up the new artwork within a few minutes without any URL change. See Updating a live design.
- Every delivery consumes bandwidth, and bandwidth is capped by your plan separately from credits. It is measured on what is sent to the viewer, so cache hits count too — a variant rendered once and then served a million times costs 1 credit and a million images' worth of bandwidth. This is usually the limit a high-traffic campaign meets first.
Updating a live design
Editing and saving a design that a dynamic image points at refreshes the artwork behind every URL you have already published. Saving queues a CDN invalidation for the whole dynamic image, not for individual variants, so every query string served from it is refreshed at once. No URL changes, and nothing you have sent out has to be re-sent.
Two consequences worth planning for:
- Refreshed variants are re-rendered, and re-rendering bills. A variant that was free while cached costs 1 credit again the next time it is requested after a save. Saving a design behind a large campaign re-bills that campaign as its traffic returns.
- Propagation is not instant. Invalidations are queued and typically complete within a few minutes. Until one completes, viewers may still be served the previous artwork.
Pre-generate finite datasets
If your variants come from a finite dataset (a product catalog, a recipient list) and loading speed matters, request every variant once upfront — a simple script hitting each URL. The CDN cache is then hot, and end users are served straight from it: no render latency, no generation at display time.
Related
- Create a Dynamic Image by API — mint the base URL
- Credits — what a variant costs, and what happens when the balance runs out
- Image Generation via URL — the query-string grammar, and which file type a variant serves
- Element Properties — every overridable property per layer type
- Help center: creating dynamic images — the dashboard walkthrough
