Content extensions

What are content extensions? Why create one?

A content extension imports third-party content, such as photos and illustrations, into Canva. Users can access this content via the side panel and add it to their designs.

To create a content extension from scratch, check out the Quick start guide.

Examples of content extensions

These are some examples of apps with content extensions:

  • Brandfetch - Easily add company logos to your design.

  • Dropbox - Add Dropbox photos to your designs.

  • Giphy - Add GIFs to your designs. Powered by GIPHY.

You can find more examples at canva.com/apps.

How users experience content extensions

Users can find apps with content extensions via the More tab.

When a user opens a content extension, the app is pinned to the left side of the screen and the content appears in the side panel. The user can then drag content into their design.

With additional configuration, a content extension can also:

How content extensions work

At its most basic, a content extension is a REST API.

Canva expects this API to have the following endpoint:

As a user interacts with a content extension via Canva's UI, Canva sends requests to this endpoint and expects to receive responses in a format that it understands. Based on these responses, Canva knows what content to render in the side panel.

Supported content types

A content extension can provide users with two types of content:

  • Images, such as JPEG, PNG, and SVG files.

  • Embeds, such as animated GIFs, YouTube videos, and Instagram photos.

A content extension can't provide users with images and embeds. It must be one or the other.

Request-response cycle

This is the request-response cycle of a content extension:

Canva sends additional requests if the extension supports authentication.

Example

const axios = require('axios');
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.static('public'));
app.post('/content/resources/find', async (request, response) => {
const { data } = await axios.get('https://picsum.photos/v2/list');
const resources = data.map((resource) => {
return {
type: 'IMAGE',
id: resource.id,
name: resource.author || resource.id,
thumbnail: {
url: resource.download_url,
},
url: resource.download_url,
contentType: 'image/jpeg',
};
});
response.send({
type: 'SUCCESS',
resources,
});
});
app.listen(process.env.PORT || 3000);