Get design analytics page views

Get analytics for individual pages in a design.

This API is currently provided as a preview. Be aware of the following:

  • There might be unannounced breaking changes.
  • Any breaking changes to preview APIs won't produce a new API version.
  • Public integrations that use preview APIs will not pass the review process, and can't be made available to all Canva users.

To use this API, your integration must act on behalf of a user who is a member of a Canva Enterprise(opens in a new tab or window) organization.

Lists the page-level view duration data for a design.

The request body can include page filters and pagination controls.

HTTP method and URL path

POST https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views

This operation is rate limited to 100 requests per minute for each user of your integration.

Authentication and authorization

This endpoint requires a valid access token that acts on behalf of a user.

Scopes

The access token must have all the following scopes (permissions):

  • design:content:read

Capabilities

The user must have at least one of the following capabilities:

  • analytics

Header parameters

Authorizationstring
Required

Provides credentials to authenticate the request, in the form of a Bearer token.

For example: Authorization: Bearer {token}

Content-Typestring
Required

Indicates the media type of the information sent in the request. This must be set to application/json.

For example: Content-Type: application/json

Path parameters

designIdstring
Required

The design ID.

Body parameters

page_idsstring[]
Required

The design page IDs to retrieve view duration data for.

Minimum items: 1

Maximum items: 100

limitinteger
Optional

The maximum number of page results to return per page.

Minimum: 1

Maximum: 100

Default value: 50

continuationstring
Optional

If the success response contains a continuation token, there are more page results you can list. You can use this token in the request body and retrieve more page results from the list.

To retrieve all page results, you might need to make multiple requests.

filterPageViewFilter
Optional

A filter for page view data.

typestring
Required

Available values: The only valid value is by_viewer.

viewer_idstring
Required

The viewer ID to filter by.

link_idstring
Optional

Filters to viewer traffic from a specific trackable link. Omit this field to target viewer traffic that did not come from a trackable link.

typestring
Required

Available values: The only valid value is for_editor.

Example request

Examples for using the /v1/designs/{designId}/analytics/page-views endpoint:

curl --request POST 'https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views' \
--header 'Authorization: Bearer {token}' \
--header 'Content-Type: application/json' \
--data '{
"page_ids": [
"PBBKfZml7MRHRQVw",
"PBBKfZml7Mghjsdg"
],
"limit": 50,
"continuation": "RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN",
"filter": {
"type": "by_viewer",
"link_id": "hddb98a3716",
"viewer_id": "b2d44753-f996-46ff-8f01-d4143911550f"
}
}'
SH
const fetch = require("node-fetch");
fetch("https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views", {
method: "POST",
headers: {
"Authorization": "Bearer {token}",
"Content-Type": "application/json",
},
body: JSON.stringify({
"page_ids": [
"PBBKfZml7MRHRQVw",
"PBBKfZml7Mghjsdg"
],
"limit": 50,
"continuation": "RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN",
"filter": {
"type": "by_viewer",
"link_id": "hddb98a3716",
"viewer_id": "b2d44753-f996-46ff-8f01-d4143911550f"
}
}),
})
.then(async (response) => {
const data = await response.json();
console.log(data);
})
.catch(err => console.error(err));
JS
import java.io.IOException;
import java.net.URI;
import java.net.http.*;
public class ApiExample {
public static void main(String[] args) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views"))
.header("Authorization", "Bearer {token}")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"page_ids\": [\"PBBKfZml7MRHRQVw\", \"PBBKfZml7Mghjsdg\"], \"limit\": 50, \"continuation\": \"RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN\", \"filter\": {\"type\": \"by_viewer\", \"link_id\": \"hddb98a3716\", \"viewer_id\": \"b2d44753-f996-46ff-8f01-d4143911550f\"}}"))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}
JAVA
import requests
headers = {
"Authorization": "Bearer {token}",
"Content-Type": "application/json"
}
data = {
"page_ids": [
"PBBKfZml7MRHRQVw",
"PBBKfZml7Mghjsdg"
],
"limit": 50,
"continuation": "RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN",
"filter": {
"type": "by_viewer",
"link_id": "hddb98a3716",
"viewer_id": "b2d44753-f996-46ff-8f01-d4143911550f"
}
}
response = requests.post("https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views",
headers=headers,
json=data
)
print(response.json())
PY
using System.Net.Http;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views"),
Headers =
{
{ "Authorization", "Bearer {token}" },
},
Content = new StringContent(
"{\"page_ids\": [\"PBBKfZml7MRHRQVw\", \"PBBKfZml7Mghjsdg\"], \"limit\": 50, \"continuation\": \"RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN\", \"filter\": {\"type\": \"by_viewer\", \"link_id\": \"hddb98a3716\", \"viewer_id\": \"b2d44753-f996-46ff-8f01-d4143911550f\"}}",
Encoding.UTF8,
"application/json"
),
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
};
CSHARP
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
payload := strings.NewReader(`{
"page_ids": [
"PBBKfZml7MRHRQVw",
"PBBKfZml7Mghjsdg"
],
"limit": 50,
"continuation": "RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN",
"filter": {
"type": "by_viewer",
"link_id": "hddb98a3716",
"viewer_id": "b2d44753-f996-46ff-8f01-d4143911550f"
}
}`)
url := "https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views"
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer {token}")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
GO
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views",
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer {token}',
'Content-Type: application/json',
),
CURLOPT_POSTFIELDS => json_encode([
"page_ids" => [
"PBBKfZml7MRHRQVw",
"PBBKfZml7Mghjsdg"
],
"limit" => 50,
"continuation" => "RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN",
"filter" => [
"type" => "by_viewer",
"link_id" => "hddb98a3716",
"viewer_id" => "b2d44753-f996-46ff-8f01-d4143911550f"
]
])
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if (empty($err)) {
echo $response;
} else {
echo "Error: " . $err;
}
PHP
require 'net/http'
require 'uri'
url = URI('https://api.canva.com/rest/v1/designs/{designId}/analytics/page-views')
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request['Authorization'] = 'Bearer {token}'
request['Content-Type'] = 'application/json'
request.body = <<REQUEST_BODY
{
"page_ids": [
"PBBKfZml7MRHRQVw",
"PBBKfZml7Mghjsdg"
],
"limit": 50,
"continuation": "RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN",
"filter": {
"type": "by_viewer",
"link_id": "hddb98a3716",
"viewer_id": "b2d44753-f996-46ff-8f01-d4143911550f"
}
}
REQUEST_BODY
response = http.request(request)
puts response.read_body
RUBY

Success response

If successful, the endpoint returns a 200 response with a JSON body with the following parameters:

itemsPageViewDuration[]

The list of page view durations.

total_view_duration_secondsinteger

The total time spent viewing this page, in seconds.

page_idstring
Optional

The page ID. This is omitted for design types that do not support page IDs.

average_duration_secondsnumber
Optional

The average time spent viewing this page, in seconds. This is omitted for by_viewer filters.

unique_view_countinteger
Optional

The number of unique viewers for this page. This is omitted for by_viewer filters.

continuationstring
Optional

If the success response contains a continuation token, there are more page results you can list. You can use this token in the request body and retrieve more page results from the list.

To retrieve all page results, you might need to make multiple requests.

Example response

{
"items": [
{
"page_id": "PBBKfZml7MRHRQVw",
"total_view_duration_seconds": 1860,
"average_duration_seconds": 21.5,
"unique_view_count": 87
}
],
"continuation": "RkFGMgXlsVTDbMd:MR3L0QjiaUzycIAjx0yMyuNiV0OildoiOwL0x32G4NjNu4FwtAQNxowUQNMMYN"
}
JSON

Error responses

400 Bad Request

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error responses

Failed to read request body
{
"code": "bad_request_body",
"message": "Failed to read request body"
}
JSON
The page views filter is invalid.
{
"code": "bad_request_body",
"message": "filter must include a valid type discriminator and required fields"
}
JSON
The continuation token is invalid or expired.
{
"code": "invalid_field",
"message": "Invalid continuation token"
}
JSON

401 Unauthorized

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error response

Access token could not be decoded or signature could not be verified.
{
"code": "invalid_access_token",
"message": "Access token is invalid"
}
JSON

403 Forbidden

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error response

The caller is not allowed to access design analytics.
{
"code": "permission_denied",
"message": "Not allowed to access analytics for this design"
}
JSON

404 Not Found

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error response

The design was not found, or analytics are unavailable.
{
"code": "design_not_found",
"message": "Design not found or analytics are not available for this design"
}
JSON

429 Too Many Requests

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error response

Rate limit exceeded
{
"code": "too_many_requests",
"message": "Too many requests to {operation}"
}
JSON

Try it out

This uses your live Canva data.

This is not a sandbox/playground. This form performs API requests against your account's actual live Canva data. Make sure that you understand what the request is doing, as well as the requirements for each parameter detailed above.

Step 1: Enter your access token

To get started, generate an access token or provide your own below