Custom File Storage
This is only required if you want to host the files somewhere other than Amazon S3. Amazon S3 is supported out of the box and requires no code. You can simply add your AWS Keys and Bucket info under project settings.
By default, we have file storage support built-in with Amazon S3 that can be configured without any coding. If you need to store files somewhere other than Amazon S3 such as your local data center or your own cloud, it can be done by the following way.
Image Upload Callback
Register this callback function to handle image uploads. The AI Assistant also uses it for image attachments and for generated or edited images applied to the design. Multiple chat attachments invoke the callback once per file, in selection order. Return a URL that Unlayer’s AI service can fetch; an expired or private network URL cannot be used for image editing. See AI image storage and limits.
The callback stores attachment bytes in your storage. Unlayer may record the returned URL in the File Manager. Generated and edited previews are initially hosted by Unlayer; applying one to the design passes it through this callback.
unlayer.registerCallback('image', function (file, done) {
// Handle file upload here
});
The function returns 2 parameters. We'll call them file and done.
| Parameter | Type | |
|---|---|---|
| file | Object | Contains an array, attachments. |
| done | Function | This is the callback function to update progress bar and handling upload completion. |
Updating Progress Bar
You can call the done callback and pass an object with progress parameter containing the percentage of completion.
unlayer.registerCallback('image', function (file, done) {
// File upload code goes here
done({ progress: 10 }); // Updates the progress bar to 10%
});
Finishing Upload
Once the upload has finished, pass the URL of the image to Unlayer. Passing an HTTP(S) URL without progress also completes the upload. Local blob: or data: previews remain pending until progress: 100; include a progress value below 100 for a hosted preview.
unlayer.registerCallback('image', function (file, done) {
// File upload code goes here
done({ progress: 100, url: 'URL OF THE FILE' });
});
Aborting or Failing an Upload
If your upload cannot complete — for example, the file fails a custom validation check, your storage backend returns an error, or the user cancels — you can reset the upload state instead of passing a URL. Pass abort or error to done:
| Signal | Result |
|---|---|
done({ abort: true }) | Silently resets the upload back to its default state, with no error shown. |
done({ error: true }) | Resets the upload and shows a generic "Upload Failed" state. |
done({ error: 'Custom message' }) | Resets the upload and shows the "Upload Failed" state with your custom message. |
Use abort when the user backs out or you handle the error yourself (e.g. in your own modal), and error when you want the builder to surface the failure.
unlayer.registerCallback('image', function (file, done) {
// Reject unsupported file types with your own validation
if (!isSupportedImage(file.attachments[0])) {
done({
error: 'Only JPG, PNG, GIF, SVG, or WebP files under 5 MB are supported.',
});
return;
}
// ... upload logic, then done({ progress: 100, url: '...' })
});
unlayer.registerCallback('image', function (file, done) {
showMyCustomErrorModal(); // you handle the error UI yourself
done({ abort: true }); // just reset the builder's upload state
});
Both abort and error are optional and fully backward compatible — existing callbacks that pass { url } are unaffected.
Full Sample Code
We will use fetch to upload the file in this sample code. We'll post it to /uploads on our server. The following is a complete sample code that handles a file upload.
unlayer.registerCallback('image', function (file, done) {
var data = new FormData();
data.append('file', file.attachments[0]);
fetch('/uploads', {
method: 'POST',
headers: {
Accept: 'application/json',
},
body: data,
})
.then((response) => {
// Make sure the response was valid
if (response.status >= 200 && response.status < 300) {
return response;
} else {
var error = new Error(response.statusText);
error.response = response;
throw error;
}
})
.then((response) => {
return response.json();
})
.then((data) => {
// Pass the URL back to Unlayer to mark this upload as completed
done({ progress: 100, url: data.filelink });
});
});