Assets
An asset is a file that exists in Canva's backend, such as an image, video, or audio file. Apps can upload, download, and otherwise interact with assets in a variety of ways.
Asset types
Apps can interact with the following types of assets:
The type of asset affects how an app can interact with it. For example, apps can upload and download image assets, but can only use font assets when creating text — they can't upload or download font assets.
The following table indicates how apps can interact with each type of asset:
Upload | Download | Use | |
---|---|---|---|
Audio | |||
Fonts | |||
Images | |||
Videos |
Asset ownership
There are two kinds of assets:
- Public assets
- Private assets
There are some differences in how apps can interact with each kind of asset.
Public assets
A public asset is one that's owned by Canva — that is, it was uploaded by Canva and is available to most users (with some restrictions, depending on how the asset was licensed). These assets appear in the Elements tab.
In certain contexts, apps can download public assets, but they can never upload them.
Private assets
A private asset is one that was uploaded by a user and exists within their media library. The user owns the asset and no one else has access to it unless they choose to share it. These assets appear in the Uploads tab.
In certain contexts, apps can upload and/or download private assets.
Asset references
All assets have an asset reference, also known as a ref.
A ref is a unique identifier that points to an asset in Canva's backend.
Refs are used throughout the Apps SDK in a variety of contexts. For example, when an asset is uploaded, a ref for that asset is returned and can be used to then interact with that asset:
import { upload } from "@canva/asset";// Upload an image assetconst asset = await upload({type: "image",mimeType: "image/jpeg",url: "https://example.com/image.jpg",thumbnailUrl: "https://example.com/thumbnail.jpg",aiDisclosure: "none",});// Use the ref of the assetconsole.log(asset.ref);
Similarly, refs can sometimes be retrieved for existing assets, such as when selecting a font from a font picker.
The various ways that refs can be used are explained throughout the documentation.
Important: Refs are opaque strings
Refs are opaque strings and apps shouldn't rely on them remaining the same. In practice, this means that apps should only use refs soon after they're created or retrieved and should not store them for later use.
Apps can upload private assets to a user's media library. When the upload succeeds or fails, a toast notification is shown to the user. (The notification itself is not customizable.)
import { upload } from "@canva/asset";await upload({type: "audio",title: "Example audio",mimeType: "audio/mp3",durationMs: 86047,url: "https://example.com/audio.mp3",aiDisclosure: "none",});
import { upload } from "@canva/asset";await upload({type: "image",mimeType: "image/jpeg",url: "https://example.com/image.jpg",thumbnailUrl: "https://example.com/thumbnail.jpg",aiDisclosure: "none",});
import { upload } from "@canva/asset";await upload({type: "video",mimeType: "video/mp4",url: "https://example.com/video.mp4",thumbnailImageUrl: "https://example.com/thumbnail-image.jpg",thumbnailVideoUrl: "https://example.com/thumbnail-video.mp4",aiDisclosure: "none",});
All assets must comply with Canva's Acceptable Use Policy(opens in a new tab or window).
Supported file formats
When uploading assets, the following file formats are supported:
Name | MIME type | Common file extensions |
---|---|---|
MPEG | "audio/mpeg" | .mpg, .mpeg, .mp1, .mp2, .mp3 |
MP4 Audio | "audio/mp4" | .mp4, .m4a |
M4A | "audio/x-m4a" | .m4a |
MP3 | "audio/mp3" | .mp3 |
OGG | "audio/ogg" | .ogg, .oga |
WAV | "audio/wav" | .wav |
X-WAV | "audio/x-wav" | .wav |
WEBM | "audio/webm" | .webm |
Name | MIME type | Common file extensions |
---|---|---|
HEIC | "image/heic" | .heic |
JPEG | "image/jpeg" | .jpg, .jpeg |
PNG | "image/png" | .png |
SVG | "image/svg+xml" | .svg |
TIFF | "image/tiff" | .tiff, .tif |
WebP | "image/webp" | .webp |
In the Apps SDK, GIFs are considered to be videos, not images.
Name | MIME type | Common file extensions |
---|---|---|
AVI | "video/avi" | .avi |
GIF | "image/gif" | .gif |
M4V | "video/x-m4v" | .m4v |
Matroska | "video/x-matroska" | .mkv |
QuickTime | "video/quicktime" | .mov |
MP4 | "video/mp4" | .mp4 |
MPEG | "video/mpeg" | .mpg, .mpeg |
WebM | "video/webm" | .webm |
In video files, transparent or translucent pixels are converted to black pixels.
File size limits
When uploading assets, the following file size limits apply:
Asset type | Maximum file size |
---|---|
Audio | 50 MB |
Images (Raster) | 50 MB |
Images (SVG) | 3 MB |
Videos | 100 MB |
Asset URLs
When uploading an asset, the asset is downloaded via Canva's backend. For this reason, asset URLs must be available via the public internet — that is, they can't be uploaded from localhost
URLs.
Thumbnail URLs
When uploading image and video assets, a thumbnail must be provided. In the case of videos, a preview video can also be provided. These thumbnails and previews are shown to the user:
- in the Uploads tab
- in the editor, while the asset is uploading
For security reasons, the URLs of these thumbnails and previews must support Cross-Origin Resource Sharing (CORS). If CORS is not supported, the URLs won't load and an error will appear in the JavaScript Console.
AI disclosure
When uploading assets, apps must disclose if the asset was created or significantly altered with AI. This helps users make informed decisions about the content they interact with.
These are some examples of when AI usage must be disclosed:
- Generating a new image from scratch
- Changing the style of an image
- Removing an object and replacing it with new content
- Changing facial expressions of people
- Compositing multiple images together
- Expanding images by generating content at the edges
- Replacing backgrounds with generated content
These are some examples of when AI usage does not require disclosure:
- Using existing assets from an asset library
- Correcting red eyes
- Removing backgrounds without replacement
- Changing object colors
- Detecting image defects and suggesting fixes
- Adjusting brightness and contrast
- Upscaling images
If the app used AI to create or alter an asset, set aiDisclosure
to "app_generated"
:
import { upload } from "@canva/asset";const asset = await upload({type: "image",mimeType: "image/jpeg",url: "https://example.com/ai-generated-image.jpg",thumbnailUrl: "https://example.com/ai-generated-thumbnail.jpg",aiDisclosure: "app_generated",});
Otherwise, set aiDisclosure
to "none"
:
import { upload } from "@canva/asset";const asset = await upload({type: "image",mimeType: "image/jpeg",url: "https://example.com/ai-generated-image.jpg",thumbnailUrl: "https://example.com/ai-generated-thumbnail.jpg",aiDisclosure: "none",});
Checking upload progress
Apps can detect when an asset has finished uploading. An example of how an app might use this behavior is to render a loading state while the upload is in progress.
import { upload } from "@canva/asset";import { addAudioTrack } from "@canva/design";// Upload an audio assetconst asset = await upload({type: "audio",title: "Example audio",mimeType: "audio/mp3",durationMs: 86047,url: "https://example.com/audio.mp3",aiDisclosure: "none",});// Wait for the upload to completeawait asset.whenUploaded();
import { upload } from "@canva/asset";// Upload an image assetconst asset = await upload({type: "image",mimeType: "image/jpeg",url: "https://example.com/image.jpg",thumbnailUrl: "https://example.com/thumbnail.jpg",aiDisclosure: "none",});// Wait for the upload to completeawait asset.whenUploaded();
import { upload } from "@canva/asset";// Upload a video assetconst asset = await upload({type: "video",mimeType: "video/mp4",url: "https://example.com/video.mp4",thumbnailImageUrl: "https://example.com/thumbnail-image.jpg",thumbnailVideoUrl: "https://example.com/thumbnail-video.mp4",aiDisclosure: "none",});// Wait for the upload to completeawait asset.whenUploaded();
What's possibly surprising though is that apps don't have to wait for the upload to complete before the asset reference is available. Apps can use the asset reference as soon as the upload starts.
import { upload } from "@canva/asset";import { addAudioTrack } from "@canva/design";// Upload an audio assetconst asset = await upload({type: "audio",title: "Example audio",mimeType: "audio/mp3",durationMs: 86047,url: "https://example.com/audio.mp3",aiDisclosure: "none",});// You can use the asset reference immediatelyconsole.log(asset.ref);// Use the asset reference to add an audio trackawait addAudioTrack({ref: asset.ref,});
import { upload } from "@canva/asset";import { addElementAtPoint } from "@canva/design";// Upload an image assetconst asset = await upload({type: "image",mimeType: "image/jpeg",url: "https://example.com/image.jpg",thumbnailUrl: "https://example.com/thumbnail.jpg",aiDisclosure: "none",});// You can use the asset reference immediatelyconsole.log(asset.ref);// Use the asset reference to add an image elementawait addElementAtPoint({type: "image",ref: asset.ref,});
import { upload } from "@canva/asset";import { addElementAtPoint } from "@canva/design";// Upload a video assetconst asset = await upload({type: "video",mimeType: "video/mp4",url: "https://example.com/video.mp4",thumbnailImageUrl: "https://example.com/thumbnail-image.jpg",thumbnailVideoUrl: "https://example.com/thumbnail-video.mp4",aiDisclosure: "none",});// You can use the asset reference immediatelyconsole.log(asset.ref);// Use the asset reference to add a video elementawait addElementAtPoint({type: "video",ref: asset.ref,});
Handling errors
A range of errors may occur when uploading assets. For example, if the user doesn't have enough storage space in their media library, a "quota_exceeded"
error will be thrown:
import { upload } from "@canva/asset";import { CanvaError } from "@canva/error";try {const asset = await upload({type: "image",mimeType: "image/jpeg",url: "https://example.com/image.jpg",thumbnailUrl: "https://example.com/thumbnail.jpg",aiDisclosure: "none",});await asset.whenUploaded();} catch (error) {if (error instanceof CanvaError) {if (error.code === "quota_exceeded") {console.error("The user is out of storage space.");} else {console.error("An error occurred:", error.code);}}}
Some errors propagate from whenUploaded
, so we recommend wrapping both methods in a try/catch block.
To learn more about handling errors in general, see Handling errors.
Downloading assets
In some contexts, apps can download assets. For example, when a user selects image or video content, an app can detect the selection of that content and download the underlying media.
Getting asset URLs
Apps can use an asset's ref to generate a temporary URL for an asset. The app can then use this URL to download the underlying media. For security reasons, asset URLs expire after a short period of time.
Apps should use asset URLs as soon as possible, rather than storing them for later use.
import { getTemporaryUrl } from "@canva/asset";const imageRef = "..." as any; // Placeholder for the ref of the imageconst { url } = await getTemporaryUrl({type: "image",ref: imageRef,});console.log(url);
import { getTemporaryUrl } from "@canva/asset";const videoRef = "..." as any; // Placeholder for the ref of the videoconst { url } = await getTemporaryUrl({type: "video",ref: videoRef,});console.log(url);
Downloading assets via the frontend
The simplest way to download assets is via the frontend. The main downside of this approach is that it's impractical to process large files via the frontend, such as videos. It also consumes more of the user's bandwidth.
import { getTemporaryUrl } from "@canva/asset";const imageRef = "..." as any; // Placeholder for the ref of the imageconst { url } = await getTemporaryUrl({type: "image",ref: imageRef,});// Download the image using the Fetch APIconst response = await fetch(url);const blob = await response.blob();
import { getTemporaryUrl } from "@canva/asset";const videoRef = "..." as any; // Placeholder for the ref of the videoconst { url } = await getTemporaryUrl({type: "video",ref: videoRef,});// Download the video using the Fetch APIconst response = await fetch(url);const blob = await response.blob();
Downloading assets via the backend
The most versatile option is to pass the URL of the asset to the app's backend and download it there. This allows the app to process larger files in more complex ways, but it does require more code and infrastructure.
import { getTemporaryUrl } from "@canva/asset";const imageRef = "..." as any; // Placeholder for the ref of the image// Get a temporary URL for the imageconst { url } = await getTemporaryUrl({type: "image",ref: imageRef,});// Send the URL to your backendawait fetch("https://your-backend.com/process-image", {method: "POST",headers: {"Content-Type": "application/json",},body: JSON.stringify({ imageUrl: url }),});
import { getTemporaryUrl } from "@canva/asset";// Get a temporary URL for the videoconst { url } = await getTemporaryUrl({type: "video",ref: videoRef,});// Send the URL to your backendawait fetch("https://your-backend.com/process-video", {method: "POST",headers: {"Content-Type": "application/json",},body: JSON.stringify({ videoUrl: url }),});
Deriving assets
A common pattern for apps is to download an asset, modify it in some way, and then upload a new asset. For example, an app might download and apply an effect to an image.
When a new asset is created from an existing asset, it's known as a derived asset, and when an app uploads a derived asset, it must provide the ref of the asset it was derived from. We verify this during the app review process.
The following code sample demonstrates the basic flow of deriving an asset:
import { upload, getTemporaryUrl } from "@canva/asset";const originalImageRef = "..." as any; // Placeholder for the ref of the original image// Get the original imageconst { url } = await getTemporaryUrl({type: "image",ref: originalImageRef,});// Process the image in some wayconst response = await fetch("https://your-backend.com/process-image", {method: "POST",body: JSON.stringify({ imageUrl: url }),});const { processedImageUrl } = await response.json();// Upload the processed image as a derived assetconst derivedAsset = await upload({type: "image",mimeType: "image/jpeg",url: processedImageUrl,thumbnailUrl: processedImageUrl,aiDisclosure: "none",parentRef: originalImageRef,});
This is required because Canva licenses assets from a number of creators and it's only by providing the ref of existing assets that Canva can ensure these licensing requirements are met.
A side-effect of this requirement is that apps are not allowed to combine multiple assets into a single asset, as the mechanism we use to track asset licensing only supports individual derived assets.