Key takeaways
- Authorize and validate the uploader before creating an Assembly; successful image processing is not moderation approval.
- Strip embedded metadata from the delivery derivative while preserving any required source evidence under a separate retention policy.
- Use a unique path with asset_id and assembly.id so retries cannot overwrite reviewed images; pair it with an application deduplication check.
A user-generated image pipeline needs more than inexpensive object storage. The application must know which upload was accepted, which derivative policy ran, where the result lives, and whether it may be delivered. Collision-free Backblaze paths and a narrow application key keep storage retries separate from moderation and product state.
What matters most
- Restrict the B2 standard application key to the destination bucket and a stable output prefix such as community/web-v1/ that covers every path the Template generates.
- Use X-Bz-Info-* headers for stable workflow labels, not private user data or arbitrary unencoded filenames.
- Serve or authorize the finished object through the application’s delivery layer instead of treating the store result URL as the product permission model.
Make moderation and processing separate states
A valid image is not necessarily content the product should expose. Record the uploader, tenant, source checksum, moderation state, and processing operation before starting the Assembly. The image workflow can normalize pixels and remove embedded metadata, but the application must decide whether the subject, ownership, and context satisfy its policy.
Keep states such as uploaded, processing, review required, approved, rejected, and export failed distinct. Do not mark content approved merely because /image/resize and /backblaze/store succeeded, and do not turn a processing error into a moderation rejection. Each state needs its own retry, review, and retention behavior.
Build the versioned Backblaze image Template
The Template accepts one bounded upload, creates a WebP derivative that fits within the chosen dimensions, strips embedded image metadata, and exports only that derivative. zoom is false, so a smaller source remains smaller. The destination path contains a version label and assembly.id, so each Assembly generates a collision-free path rather than overwriting a previously reviewed image.
The application supplies a validated asset_id, but it does not choose a credential, bucket, arbitrary prefix, or Robot parameters. Keep allow_steps_override false and use the Template auth limits as a final workload boundary. Preserve an original separately when appeals, reprocessing, or legal requirements need source evidence; strip affects the derivative, not an external source archive.
{
"allow_steps_override": false,
"auth": {
"max_number_of_files": 1,
"max_size": 26214400
},
"steps": {
":original": {
"robot": "/upload/handle"
},
"community_webp": {
"use": ":original",
"robot": "/image/resize",
"width": 2048,
"height": 2048,
"resize_strategy": "fit",
"zoom": false,
"format": "webp",
"quality": 80,
"strip": true
},
"backblaze_versioned": {
"use": "community_webp",
"robot": "/backblaze/store",
"credentials": "backblaze-community-images",
"path": "community/web-v1/${fields.asset_id}/${assembly.id}/${file.url_name}",
"headers": {
"X-Bz-Info-workflow": "community-web-v1"
},
"result": true
}
}
}Restrict the Backblaze application key
Create a standard application key rather than using the master key. Restrict it to the destination bucket and a stable output prefix such as community/web-v1/ that covers every path the Template generates. The Backblaze store documentation calls for listBuckets, writeFiles, and listFiles so the Robot can resolve the bucket and upload the object.
A prefix restriction and unique destination paths reduce impact if the credential is exposed, but they do not authorize an application user or moderate content. Store the bucket, application key ID, and application key in named Template Credentials. Rotate or revoke that credential independently of application login sessions and test the replacement before removing the old key.
Bucket boundary
The key cannot operate against unrelated buckets.
Prefix boundary
The key is limited to objects beneath the derivative namespace.
Application boundary
The product still decides which tenant and asset may invoke the Template.
Use paths and file information deliberately
Backblaze B2 object names form a flat namespace even when tools present slash-separated prefixes as folders. Use those prefixes for organization and key restriction, not as proof that parent directories exist. Include a workflow version and bounded application identifier in the path, and use assembly.id to prevent name collisions.
/backblaze/store accepts string-valued headers, including X-Bz-Info-* file information. Use stable labels such as the derivative workflow version. Do not insert private user data, secrets, or an unbounded original filename. The Robot rejects a generated file name longer than 1,024 UTF-8 bytes, so every application field that enters the path must have a length and character contract.
Test the derivative and destination failure model
Exercise orientation, transparency, animation, color profiles, large dimensions, malformed files, duplicate submissions, invalid application keys, a key restricted to the wrong prefix, and an unavailable bucket. Inspect appearance, format, dimensions, bytes, metadata stripping, object path, and file information rather than accepting a green Assembly alone.
Track failures by intake, processing, authentication, bucket lookup, and upload. An uncertain timeout should enter reconciliation because the object may already exist. Check the original Assembly and operation record before creating a new versioned path, or the product can accumulate multiple approved-looking derivatives for one source.
Keep storage URLs separate from delivery authorization
A result URL identifies what the store Step returned; it is not the application’s tenant or moderation policy. Keep the object unavailable to product consumers until the application reconciles it with the expected operation and advances the moderation state. Deliver through the bucket and CDN configuration chosen for the product, with authorization applied at that boundary.
Retain the durable bucket and object name, workflow version, Assembly ID, source identity, and moderation decision. Delete rejected or superseded derivatives through a separate retention process that understands Backblaze file versions and the product’s audit requirements. The processing Template should not make that destructive decision.
Technical details worth knowing
- /backblaze/store requires bucket, app key ID, and app key values, which can be supplied through named Template Credentials.
- The /backblaze/store documentation states that the bucket needs listBuckets permission to resolve its ID, plus writeFiles and listFiles.
- Backblaze standard application keys can be restricted to a bucket and file-name prefix; the prefix must cover the path generated by the Template.
- /backblaze/store accepts a path with Assembly Variables and a string-valued headers object. X-Bz-Info-* headers become Backblaze file information.
- Backblaze B2 object names are flat strings; slash-delimited folders are prefixes presented as a hierarchy by tools and interfaces.
- The Robot rejects generated Backblaze file names longer than 1,024 UTF-8 bytes; the limit counts encoded bytes, not characters.
A practical approach
- 1
Define upload limits, moderation states, target format, metadata policy, and a stable destination prefix.
- 2
Create a prefix-restricted Backblaze application key and save it as named Template Credentials.
- 3
Run representative mobile, transparent, animated, malformed, and metadata-heavy image fixtures.
- 4
Persist the B2 object identity before changing application state, and retry by operation rather than by filename.
When Transloadit is useful
Use /upload/handle for one moderated intake candidate, /image/resize for a bounded metadata-stripped WebP, and /backblaze/store for a unique versioned path. Use a standard B2 application key restricted to the destination bucket and a stable output prefix, and place stable workflow metadata in X-Bz-Info-* headers.
Architecture boundary
Transloadit accepts a community image, creates the storage-efficient rendition, and writes it to a Backblaze B2 bucket. The application remains responsible for moderation, tenant ownership, durable source records, bucket policy, delivery authorization, and deletion.
Frequently asked questions
Does metadata stripping moderate the image?
No. It removes embedded metadata from the derivative. Content policy, ownership, and contextual review remain application responsibilities.
Should the workflow use a Backblaze master application key?
No. Use a standard key restricted to the destination bucket and a derivative prefix that covers every generated path, with the capabilities required by the Robot.
Are slash-separated paths real B2 folders?
No. B2 stores flat object names. Interfaces can present shared prefixes as folders, which is useful for organization and access restriction.
Can X-Bz-Info headers contain user data?
Avoid it. Use bounded, non-sensitive operational labels and keep private user or moderation data in the application database.
Why not overwrite the previous derivative?
Unique versioned paths make retries, moderation evidence, rollback, and cache behavior easier to reconcile. Pair them with an application deduplication check, then delete superseded versions later under an explicit retention policy.