How to Use a Custom Asset Library in an Embedded Editor
Connect a custom media library to an embedded editor by matching its asset handoff to the editor’s API. See a runnable Canva example, CKEditor options, and integration guidance.

To use a custom asset library in an embedded editor, connect the library through an integration point the editor supports—such as an asset manager, upload adapter, file-picker callback, or URL insertion feature—then hand the selected asset to the editor in the format its API expects. That format might be a URL, an opaque reference, or an editor-specific object. There is no universal implementation: the editor, its version, and the host application determine the contract.
A useful way to think about the integration is as two separate jobs: your library helps a user find and select an asset; your editor integration uploads or inserts that asset. Canva Apps documents a concrete upload-then-insert flow. CKEditor 5 documents URL insertion and asset-manager configuration as other integration options. Treat each as product-specific guidance, not interchangeable APIs.
1. Identify the editor’s integration contract
Before building a picker, check the exact editor product and version, and find its current documentation for images or assets. Look for a supported extension point:

- Built-in asset manager: configure the editor to use your library, if the editor exposes a supported integration.
- Upload adapter or callback: provide a function that receives a selected file and returns the data the editor expects.
- URL insertion: insert an image by URL when the editor supports that workflow.
- Vendor SDK: call the editor’s insertion method with its documented asset reference or object.
Record the handoff shape before implementing the picker. Is the result a publicly fetchable URL, a temporary signed URL, an opaque vendor reference, or a file object? Also establish which component uploads the file, which system stores it, and whether the editor or its backend must fetch remote URLs.
2. Decide who owns assets and identifiers
A host-managed library and a user-owned vendor library create different authorization and lifecycle requirements. With a host-managed library, your application typically controls search, permissions, storage, and stable asset IDs. With a vendor library, the editor provider may own the stored copy and provide a reference for insertion.
Define these rules explicitly:
- Who can search, select, upload, replace, and delete each asset?
- Is an asset shared across a workspace, owned by one user, or public?
- Does the editor need a stable URL, or is a short-lived URL sufficient?
- Where are durable metadata, tags, attribution, and permissions stored?
- What happens if an asset is deleted or access is revoked after insertion?
Do not use an editor-provided opaque reference as your own permanent database key unless its documentation promises that stability. Canva explicitly describes refs as opaque and says apps should not rely on them remaining the same. Keep your own asset record and map it to the vendor reference needed for the immediate operation.
3. Canva Apps example: upload, then insert
Canva’s documented pattern is to upload an image into the user’s private media library and then add it to the design with the returned ref. The app needs the canva:design:content:write and canva:asset:private:write permissions for this flow. An uploaded private asset belongs to the user’s media library.
The following illustrates the core SDK calls documented by Canva. It assumes your app has already requested the permissions, initialized Canva’s SDK, obtained an image URL that Canva can fetch, and has access to a valid design interaction point:
const uploaded = await Canva.assets.upload({
type: 'image',
mimeType: 'image/png',
url: selectedAsset.publicUrl,
thumbnailUrl: selectedAsset.thumbnailUrl,
aiDisclosure: 'none',
});
await Canva.design.addElementAtPoint({
type: 'image',
ref: uploaded.ref,
altText: selectedAsset.altText ?? '',
});
Use the exact SDK types and accepted aiDisclosure value for the SDK version in your app; the sample shows the documented flow, not a substitute for checking the current reference. The returned ref can be used while the file is uploading. Once inserted, the image can be manipulated using Canva’s normal design tools.
The URL must be reachable by Canva’s backend. A URL on your laptop’s localhost is not reachable by Canva and is unsuitable for this upload flow. For thumbnails and previews, Canva’s assets documentation calls out CORS support. If your library serves private media, use an access mechanism compatible with the editor’s fetch behavior; do not expose private assets through a permanent public URL merely to make the integration work.
Canva REST Assets API constraints
Canva’s REST Assets API is a separate option for managing assets in a user’s library. Its documented endpoint supports image and video assets, asynchronous upload jobs, upload from URL, and operations to inspect, update, or delete asset metadata. Respect its product-specific limits:
| Media | Documented size limit | Documented formats |
|---|---|---|
| Image | Smaller than 50 MB | JPEG, PNG, HEIC, single-frame GIF, TIFF, single-frame WEBP |
| Video | Smaller than 500 MB | M4V, MKV, MP4, MPEG, QuickTime, WebM |
These limits apply to Canva’s API, not to embedded editors in general. Check the current Canva reference for endpoint details, authentication, job states, and request schemas before building against it.
4. CKEditor 5 and URL-based insertion
CKEditor 5 represents a different integration family. Its documentation describes inserting an image by URL with the ImageInsert plugin and toolbar item, and separately documents an assetManager image integration option. The right choice depends on how your application’s library is exposed and which CKEditor features are configured.
For a simple URL insertion setup, install and configure the image insertion feature as described in the current CKEditor documentation, then make your picker pass the selected URL through the supported UI or editor API. A conceptual configuration looks like this:
ClassicEditor.create(document.querySelector('#editor'), {
plugins: [Essentials, Paragraph, Image, ImageInsert],
toolbar: ['undo', 'redo', 'insertImage'],
}).then(editor => {
// Your library picker should call the supported image insertion flow
// with the selected asset URL. Confirm the API for your CKEditor version.
});
This is a configuration sketch, not a complete installable application: plugin imports and build setup vary by CKEditor distribution. Consult CKEditor’s [image insertion guide](https://ckeditor.com/docs/ckeditor5/latest/features/images/images-inserting.html) and [image feature configuration](https://ckeditor.com/docs/ckeditor5/latest/features/images/images-installation.html) for the exact package and API details for your version. Avoid copying Canva’s ref handoff into CKEditor; the products use different contracts.
5. Build the library picker around the handoff
Once the editor contract is known, implement the library UI independently from the insertion step. A practical sequence is:
- Authenticate the user to your host application and load only assets they are allowed to see.
- Search by name, tags, type, or other metadata; paginate large result sets instead of loading every item.
- Show a thumbnail and useful metadata, and provide keyboard-accessible selection and confirmation.
- Validate the chosen asset’s media type, dimensions or size where relevant, and current access rights.
- Upload or resolve the asset through the editor’s supported path.
- Insert it and show a clear success or actionable error state.
- Save your own durable asset ID and any resulting editor reference with the design metadata if the application needs to reconcile later edits.
Keep the selected asset’s alt text available at insertion time. If the editor offers crop, resize, or other transformations, distinguish the original library asset from the edited instance in your data model; otherwise a user may unintentionally overwrite a shared source file.
6. Validate media, URLs, permissions, and previews
Validation should happen both in the picker and at the upload boundary. The picker can provide fast feedback, but the server or vendor API must still reject disallowed inputs safely. Check MIME type as well as filename extension, enforce the relevant size limits, and handle unsupported formats with a message that tells the user what to do.

For URL-based flows, verify that the URL is fetchable by the component that will retrieve it. Remote fetchers may not share the browser’s cookies or network access. For browser-rendered thumbnails, configure CORS as required; for private media, use a documented authenticated or signed delivery method. Never assume that a URL working in your own browser proves the editor’s service can fetch it.
For Canva, the cited documentation says the user’s media library quota is 1 TB for Canva Pro accounts and 5 GB for other Canva accounts; users see an error when they exceed the quota. These are Canva account limits and should not be applied to other providers.
7. Troubleshooting common integration failures
| Symptom | Likely cause | What to check or fix |
|---|---|---|
| Permission or authorization error | The app did not request or receive a required scope, or the user session is missing. | For the Canva private upload-and-insert example, verify both canva:asset:private:write and canva:design:content:write, then repeat the user authorization flow if scopes changed. |
| Upload cannot fetch the source URL | The URL is local, private to your network, expired, or requires browser-only credentials. | Use an internet-accessible URL that the editor’s fetcher can retrieve, or choose a supported upload mechanism. A localhost URL will not work for Canva’s backend fetch. |
| Thumbnail or preview is blocked | Cross-origin policy prevents the editor or browser from reading the preview. | Configure CORS for the relevant origin and content type as required by the editor’s documentation. |
| Unsupported media or size error | The type, frame count, or file size is outside the vendor’s limits. | Validate before upload and offer a conversion or smaller-file path. For Canva REST Assets, use the documented formats and size limits above. |
| Quota exceeded | The user’s vendor media storage is full. | Explain that the user needs to free space or use an account with available capacity. Do not treat Canva quotas as general editor limits. |
| Asset uploads but is not inserted | The insertion call used the wrong identifier, lacks design-write permission, or ran before the upload result was available. | Pass the returned ref exactly as required by the SDK, inspect upload state and error details, and call the insertion API only with the appropriate result. |
| Asset appears for the wrong user or workspace | Picker filtering or ownership checks are missing, or a vendor reference was reused across contexts. | Bind every selection to the authenticated user and workspace; re-check authorization at insertion and persistence time. |
| Works in one editor version, fails after upgrade | Plugin names, configuration, or insertion APIs changed. | Pin the editor version, review its migration notes, and verify the integration against the current official reference. |
8. Performance, reliability, and cost considerations
For performance, optimize library discovery separately from file transfer. Paginate search results, generate appropriately sized thumbnails, cache non-sensitive metadata, and avoid uploading a duplicate when an existing vendor asset can be selected. Large files can dominate perceived latency; show upload progress or a pending state and let users cancel when the API permits it. Canva’s REST uploads may be asynchronous, so design for a job state rather than assuming every upload is immediately complete.
For reliability, make upload and insertion separate observable steps. Preserve enough state to let a user retry insertion if upload succeeded but insertion failed, without uploading the same bytes again. Use idempotency support if the provider documents it; otherwise keep a local operation record and avoid blind duplicate retries. Surface vendor error identifiers in logs while keeping user-facing messages understandable.
Cost depends on where files are stored, how often they are transformed or delivered, and the editor or storage provider’s current plan and quotas. The cited research provides Canva-specific storage quotas, but no general cost or benchmark for embedded editors. Estimate your own library’s storage, egress, thumbnail generation, and API usage from its provider’s current pricing, and keep user-level quota errors distinct from application-wide limits.
Or skip the browser setup
If you need screenshots of your embedded editor or asset-picker flow for documentation, QA, or an AI workflow, ScreenshotNeo is a website screenshot API and MCP server. A single GET request returns an image or PDF, and its documentation covers the API options. For example:
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up free and get 1,000 screenshots a month with no card.
FAQ
Can I use one asset-picker implementation with every editor?
You can reuse library search and selection UI, but the final upload or insertion adapter must match each editor’s documented contract.
Should I store the editor’s asset reference in my database?
Store it only as a provider-specific mapping or operational reference when needed. Keep your own durable asset ID, especially when the provider describes refs as opaque or unstable.
Can I just pass a private image URL to the editor?
Only if the editor’s documented fetch path can authenticate to that URL. Confirm whether the browser, your server, or the vendor backend fetches it, and choose a compatible access method.
Does Canva’s 50 MB image limit apply to other editors?
No. It is a Canva REST Assets API limit; check the selected editor’s current documentation for its own accepted formats and limits.


