Skip to main content
RapidDev - Software Development Agency
flutterflow-integrationsFlutterFlow API Call

Canva

Connect FlutterFlow to Canva using the Canva Connect API — a REST API for listing brand assets, designs, and generating exports (PNG, PDF, MP4). The OAuth 2.0 client secret must be proxied through Firebase Cloud Functions. Exports are asynchronous: you POST a job, receive a job ID, then poll the proxy until the download URL is ready — never poll directly from the client.

What you'll learn

  • How to register a Canva Connect integration and obtain the OAuth 2.0 client ID and client secret
  • How to proxy the OAuth authorization code flow through a Firebase Cloud Function to keep the client secret server-side
  • How to configure FlutterFlow API Calls that communicate with your proxy endpoints instead of Canva directly
  • How to list Canva designs and brand assets and bind them to a FlutterFlow gallery ListView
  • How to trigger an asynchronous export job and poll for the completed download URL via the proxy
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced16 min read60 minutesMedia & ContentLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to Canva using the Canva Connect API — a REST API for listing brand assets, designs, and generating exports (PNG, PDF, MP4). The OAuth 2.0 client secret must be proxied through Firebase Cloud Functions. Exports are asynchronous: you POST a job, receive a job ID, then poll the proxy until the download URL is ready — never poll directly from the client.

Quick facts about this guide
FactValue
ToolCanva
CategoryMedia & Content
MethodFlutterFlow API Call
DifficultyAdvanced
Time required60 minutes
Last updatedJuly 2026

Surface Canva Assets and Exports in Your FlutterFlow App

The most important expectation to set at the start: Canva is not an embeddable design editor you can drop into a FlutterFlow screen. The Canva Connect API is a data and export layer — it lets you list a user's designs and folders, retrieve brand kit assets, and trigger asynchronous export jobs that produce download URLs for PNG, PDF, or MP4 files. If you want your users to open and edit designs inside your app, that's not what this integration provides. What it does provide is powerful enough to build brand asset galleries, auto-generated export workflows, and design management dashboards in FlutterFlow.

The entire integration requires an OAuth 2.0 proxy because the Canva Connect API uses the authorization code flow — the most secure OAuth type, but one that involves a client secret that can never live in a Flutter app bundle. The flow works like this: your Firebase Cloud Function generates the authorization URL, the user completes Canva's consent screen in a WebView (opened via a url_launcher Custom Action in FlutterFlow), Canva redirects back to your proxy with an authorization code, and the proxy exchanges it for an access token and refresh token. Tokens are stored server-side; the Flutter app never sees them.

Exports add another async layer. You POST to /exports to request a PNG or PDF of a design, receive a job ID, and must poll GET /exports/{exportId} until the status field reads 'success' — at which point the URL field contains the download link. Polling from a tight client-side loop will hit Canva's rate limits (429 Too Many Requests) quickly. The proxy should implement exponential backoff polling and return the URL to FlutterFlow only when it's ready. Canva Pro or Teams plans are required for some brand kit and advanced asset features — confirm your plan covers the endpoints you need.

Integration method

FlutterFlow API Call

FlutterFlow communicates with Canva through a Firebase Cloud Function proxy that handles the OAuth 2.0 authorization code flow and manages export polling. FlutterFlow's API Calls panel is used to call your proxy endpoints — not the Canva Connect API directly — because the OAuth client secret can never be embedded in the compiled Flutter app. The proxy exchanges tokens, polls export jobs with backoff, and returns ready-to-display download URLs to the app.

Prerequisites

  • A Canva account (Pro or Teams recommended — some brand kit and asset features require a paid plan)
  • A registered Canva Connect integration with client ID and client secret from developers.canva.com
  • A Firebase project on the Blaze (pay-as-you-go) plan to deploy Cloud Functions that proxy OAuth and export polling
  • A FlutterFlow project with at least one screen for the design gallery
  • Basic familiarity with FlutterFlow's API Calls panel and Custom Actions (url_launcher)

Step-by-step guide

1

Register a Canva Connect integration and get your credentials

Go to developers.canva.com and sign in with your Canva account. Click 'Create an integration' and fill in the integration name, description, and logo. Under OAuth 2.0 settings, add your Firebase Cloud Function URL as the redirect URI (you'll deploy the function in the next step — use a placeholder like https://us-central1-your-project.cloudfunctions.net/canvaOAuth for now and update it after deployment). Select the OAuth scopes your app needs: at minimum 'design:content:read' to list designs, 'asset:read' to access brand assets, and 'design:content:write' or 'design:meta:read' depending on your use case. After saving, copy the Client ID (public) and the Client Secret (private, shown only once — store it in your password manager immediately). The Client ID can go into your Firebase Cloud Function's environment config; the Client Secret must be stored as a Firebase Secret — never in plaintext.

Pro tip: Write down your OAuth scopes carefully during registration — changing them later requires users to re-authorize. Start with read-only scopes and add write scopes only if your app needs them.

Expected result: You have a Canva Connect integration created with a Client ID, a stored Client Secret, and a redirect URI pointing to your Firebase Cloud Function URL.

2

Deploy a Firebase Cloud Function to proxy OAuth and export polling

This is the core of the Canva integration — the proxy that handles everything sensitive: OAuth token exchange, token storage, refresh, and export status polling with backoff. The Firebase Cloud Function is deployed to your Firebase project (Blaze plan required for outbound HTTP calls in Cloud Functions). The proxy exposes three endpoints: (1) /canvaOAuth — the OAuth redirect URI that Canva calls with the authorization code; this function exchanges the code for tokens using Canva's token endpoint and stores them securely in Firestore keyed to a session or user ID. (2) /canvaApi — a pass-through that attaches the current access token (refreshing it if expired) to any Canva Connect API request and returns the response to FlutterFlow. (3) /canvaExport — triggers a POST /exports job, polls GET /exports/{exportId} with exponential backoff until status is 'success', and returns the download URL. Store your Canva Client ID and Client Secret as Firebase Secrets using the Firebase CLI: firebase functions:secrets:set CANVA_CLIENT_ID and firebase functions:secrets:set CANVA_CLIENT_SECRET. Set CANVA_REDIRECT_URI to your deployed function URL. Deploy the functions and update your Canva integration's redirect URI with the actual deployed URL. If you'd prefer to skip building this proxy yourself, RapidDev's team sets up FlutterFlow integrations like this routinely — free scoping call at rapidevelopers.com/contact.

index.js
1// Firebase Cloud Function — canvaExport endpoint (Node.js)
2const { onRequest } = require('firebase-functions/v2/https');
3const { defineSecret } = require('firebase-functions/params');
4const fetch = require('node-fetch');
5const admin = require('firebase-admin');
6
7const CANVA_CLIENT_ID = defineSecret('CANVA_CLIENT_ID');
8const CANVA_CLIENT_SECRET = defineSecret('CANVA_CLIENT_SECRET');
9
10// Poll export job with exponential backoff
11async function pollExport(accessToken, exportId, maxAttempts = 10) {
12 let delay = 2000; // start at 2 seconds
13 for (let i = 0; i < maxAttempts; i++) {
14 await new Promise((r) => setTimeout(r, delay));
15 const res = await fetch(
16 `https://api.canva.com/rest/v1/exports/${exportId}`,
17 { headers: { Authorization: `Bearer ${accessToken}` } }
18 );
19 const data = await res.json();
20 if (data.job?.status === 'success') {
21 return data.job?.urls?.[0] ?? null;
22 }
23 if (data.job?.status === 'failed') throw new Error('Export failed');
24 delay = Math.min(delay * 1.5, 15000); // cap at 15 seconds
25 }
26 throw new Error('Export timed out');
27}
28
29exports.canvaExport = onRequest(
30 { secrets: [CANVA_CLIENT_ID, CANVA_CLIENT_SECRET] },
31 async (req, res) => {
32 res.set('Access-Control-Allow-Origin', '*');
33 if (req.method === 'OPTIONS') return res.status(204).send('');
34
35 const { designId, format, userId } = req.body;
36 // Retrieve stored access token from Firestore
37 const db = admin.firestore();
38 const tokenDoc = await db.collection('canvaTokens').doc(userId).get();
39 const accessToken = tokenDoc.data()?.accessToken;
40 if (!accessToken) return res.status(401).json({ error: 'Not authenticated' });
41
42 // Start export job
43 const exportRes = await fetch('https://api.canva.com/rest/v1/exports', {
44 method: 'POST',
45 headers: {
46 Authorization: `Bearer ${accessToken}`,
47 'Content-Type': 'application/json',
48 },
49 body: JSON.stringify({
50 design_id: designId,
51 format: { type: format || 'png' },
52 }),
53 });
54 const exportData = await exportRes.json();
55 const exportId = exportData.job?.id;
56 if (!exportId) return res.status(500).json({ error: 'Export job creation failed' });
57
58 const downloadUrl = await pollExport(accessToken, exportId);
59 return res.json({ url: downloadUrl });
60 }
61);

Pro tip: The exponential backoff in pollExport starts at 2 seconds and caps at 15 seconds — Canva PNG exports typically complete in 5-20 seconds; PDF exports may take longer for complex designs.

Expected result: Your Firebase Cloud Functions are deployed and responding. Calling the canvaExport endpoint with a designId and format returns a download URL after the export job completes.

3

Configure FlutterFlow API Calls to your proxy endpoints

With the proxy running, set up FlutterFlow API Calls that communicate with your Firebase Functions — not with Canva directly. In FlutterFlow, click API Calls in the left navigation, then + Add → Create API Group. Name it 'CanvaProxy' and set the Base URL to your Firebase Cloud Functions base URL (e.g., https://us-central1-your-project.cloudfunctions.net). No shared auth headers are needed here since the proxy handles Canva authentication internally. Add three API Calls to the group: 1. 'Get Designs' — GET /canvaApi with a query parameter endpoint set to '/designs' (or pass it as a body param if your proxy uses POST). Parse the response JSON for fields like id, title, thumbnail_url, created_at, and updated_at. Map these into a FlutterFlow Data Type named 'CanvaDesign'. 2. 'Start Export' — POST /canvaExport with a JSON body containing designId (String variable), format (String, e.g., 'png'), and userId (String, the logged-in user's ID). The response will be a JSON object with a url field containing the completed download URL (the proxy blocks until the export is done). 3. 'Get Brand Assets' — GET /canvaApi with the endpoint parameter set to '/assets'. Parse asset fields (id, name, url, type) into a 'CanvaAsset' Data Type. In the Response & Test tab for each call, paste a sample response to auto-generate JSON paths. Test each call using the Test API Call button — you'll need to have at least one OAuth flow completed and a userId stored in Firestore for the export call to work.

api_group_config.json
1{
2 "Group Name": "CanvaProxy",
3 "Base URL": "https://us-central1-your-project.cloudfunctions.net",
4 "Calls": [
5 {
6 "Name": "Get Designs",
7 "Method": "GET",
8 "Endpoint": "/canvaApi",
9 "Query Params": { "endpoint": "/designs" },
10 "JSON Paths": {
11 "id": "$.items[*].id",
12 "title": "$.items[*].title",
13 "thumbnailUrl": "$.items[*].thumbnail.url",
14 "updatedAt": "$.items[*].updated_at"
15 }
16 },
17 {
18 "Name": "Start Export",
19 "Method": "POST",
20 "Endpoint": "/canvaExport",
21 "Body": {
22 "designId": "[variable:designId]",
23 "format": "[variable:format]",
24 "userId": "[variable:userId]"
25 },
26 "JSON Paths": {
27 "downloadUrl": "$.url"
28 }
29 }
30 ]
31}

Pro tip: For the export call, consider showing a loading state in FlutterFlow (a progress indicator) while waiting for the proxy to return — exports can take 5-30 seconds and the API Call will block until complete.

Expected result: The CanvaProxy API Group has three calls configured. 'Get Designs' returns a list of design objects with thumbnail URLs. 'Start Export' returns a download URL after the export completes.

4

Build the OAuth login flow with a url_launcher Custom Action

The Canva OAuth flow requires the user to open a browser to authorize your app. In FlutterFlow, this is handled by a Custom Action using the url_launcher package. When the user taps 'Connect Canva' in your app, the Custom Action opens the Canva authorization URL in the device's default browser (or a WebView). Your Firebase proxy generates the authorization URL with the correct state parameter and scopes. In FlutterFlow, go to Custom Code → + Add → Action. Name it 'LaunchCanvaOAuth'. Add url_launcher as a dependency in the Dependencies field. The action takes one String argument: authUrl (the full Canva authorization URL returned by your proxy). The Dart code calls launchUrl to open it. The user completes authorization on Canva's website, and Canva redirects to your Firebase Cloud Function redirect URI with the authorization code. The function exchanges the code for tokens and stores them in Firestore. To trigger the flow from FlutterFlow: add a 'Connect Canva' button on your account screen. Set up an Action Flow: first, make an API Call to your proxy's /canvaAuthUrl endpoint (which generates the state-signed auth URL), then pass the returned URL string to the LaunchCanvaOAuth Custom Action. After the user returns to the app (you can detect this with a deep link or by checking Firestore for a token on app resume), show the design gallery.

launch_canva_oauth.dart
1import 'package:flutter/material.dart';
2import 'package:url_launcher/url_launcher.dart';
3
4Future<void> launchCanvaOAuth(String authUrl) async {
5 final uri = Uri.parse(authUrl);
6 if (await canLaunchUrl(uri)) {
7 await launchUrl(
8 uri,
9 mode: LaunchMode.externalApplication, // opens in system browser
10 );
11 } else {
12 throw Exception('Could not launch Canva authorization URL: $authUrl');
13 }
14}

Pro tip: Use LaunchMode.externalApplication to open the system browser rather than an in-app WebView — Canva's OAuth page may block embedded WebViews for security reasons on some device configurations.

Expected result: Tapping 'Connect Canva' opens the device's browser to Canva's authorization page. After the user approves access, the proxy exchanges the code for tokens and the app can now call the designs and export endpoints.

5

Bind the design gallery to a FlutterFlow ListView and handle exports

With the API Calls configured, build the design gallery screen in FlutterFlow. Add a ListView widget to your screen. In the Generate Dynamic Children section, select Backend Query and choose your 'Get Designs' API Call from the CanvaProxy group. Pass the current user's ID if your proxy requires it for authentication. FlutterFlow will iterate over the list of CanvaDesign items returned. For each list item, add a Card widget containing: a Network Image widget bound to the CanvaDesign.thumbnailUrl field; a Text widget for the design title bound to CanvaDesign.title; and an 'Export' button. On the Export button's On Tap action, open a bottom sheet asking the user to choose a format (PNG or PDF), then call the 'Start Export' API Call with the selected design's ID, the chosen format, and the current user's ID. While the export is in progress, show a CircularProgressIndicator. When the API Call returns the download URL, either open it with a url_launcher Custom Action (for viewing in browser) or download it to the device using the http package in a Custom Action. For pulling brand assets into a separate tab, follow the same pattern with the 'Get Brand Assets' call and a separate GridView layout. Filter assets by type (image, video, audio) using a FlutterFlow Conditional Visibility rule on each card. Respect Canva's per-minute rate limits — avoid batch-exporting multiple designs simultaneously; queue exports sequentially using a Page State variable to track export progress.

Pro tip: Consider caching the returned export URL in a Firestore document keyed to the design ID and a timestamp. If the user requests the same design export again within an hour, return the cached URL to avoid triggering a new export job and burning rate limit budget.

Expected result: The design gallery shows thumbnail cards for all Canva designs from the user's workspace. Tapping 'Export' on a design card shows a loading state, then opens or downloads the exported file when the proxy returns the URL.

Common use cases

Brand asset gallery that pulls the team's Canva designs

A FlutterFlow app for marketing teams that shows all designs from a shared Canva workspace, organized by folder. Team members can browse thumbnails, see design names and last-edit dates, and tap a card to trigger a PNG export for download. The OAuth flow connects the user's Canva account on first launch.

FlutterFlow Prompt

Build a FlutterFlow gallery screen that lists all Canva designs from a team workspace, shows thumbnail previews, and lets users export a selected design as a PNG to their device.

Copy this prompt to try it in FlutterFlow

Automated certificate generator for an events app

An events platform built in FlutterFlow where attendees receive a personalized Canva-generated certificate after completing a course or attending a session. The app triggers a design export job for the attendee's name and the proxy polls until the PDF is ready, then sends the URL for download or share.

FlutterFlow Prompt

Create a FlutterFlow feature that triggers a Canva design export when a user completes a course, waits for the PDF to be ready, and shows a download button.

Copy this prompt to try it in FlutterFlow

Social media content scheduler with Canva design previews

A content management FlutterFlow app that lets social media managers browse their Canva design library, select posts for the week, export them as PNGs via the Connect API, and queue them for publishing. The design thumbnails and export status are all surfaced through the proxy-powered API Calls.

FlutterFlow Prompt

Build a FlutterFlow content planner that shows Canva designs for a week's social posts, lets the manager approve and export each one as a PNG, and marks it as ready for scheduling.

Copy this prompt to try it in FlutterFlow

Troubleshooting

429 Too Many Requests error when triggering multiple exports or listing large design libraries

Cause: Canva's Connect API enforces per-minute rate limits. Client-side polling of export status or batch-fetching designs on every screen open can exhaust these limits quickly.

Solution: Move all export polling to the Firebase Cloud Function proxy with exponential backoff (see Step 2). For design listing, implement pull-to-refresh instead of auto-refreshing on every screen navigation. Add a minimum delay between export requests if users can trigger them in quick succession — use a Page State boolean to disable the export button while a job is in progress.

OAuth authorization fails or the redirect URI shows an error after Canva authorization

Cause: The redirect URI in your Canva Connect integration registration does not exactly match the Firebase Cloud Function URL (including https:// and no trailing slash), or the OAuth state parameter is missing or mismatched.

Solution: In developers.canva.com, check your integration's redirect URI against the exact deployed Firebase Cloud Function URL. The redirect URI must be registered in Canva's developer portal before it can be used. Ensure your proxy generates and validates the state parameter to prevent CSRF. If the function URL changed after initial deployment, update the Canva integration's redirect URI in the developer portal.

Export job status stays 'in_progress' and never returns 'success'

Cause: The export job failed silently, or the design is very complex and the polling timeout was reached too early.

Solution: Check the export job status field for 'failed' in addition to 'success' and surface a meaningful error to the user. Increase the maximum polling attempts and extend the backoff cap for PDF exports (they take longer than PNG). Log the full export job response in Firebase Functions logs to identify if Canva is returning an error code in the job payload.

Thumbnail images fail to load in the FlutterFlow ListView (blank or broken image placeholders)

Cause: Canva's thumbnail URLs are signed and expire after a short period. Fetching designs and storing the thumbnail URL in Firestore for later display will break as the URL expires.

Solution: Fetch the design list fresh from the proxy each time the gallery screen is opened rather than caching thumbnail URLs. If you need offline caching, re-fetch the design list (not just the stored thumbnail URLs) to get fresh signed URLs. Implement an error fallback image in your FlutterFlow Image widget's Not Set state.

Best practices

  • Never place the Canva OAuth client secret or access tokens in FlutterFlow API Call headers — all Canva API communication must go through your Firebase Cloud Function proxy.
  • Use exponential backoff polling in the proxy for export jobs — start at 2 seconds and cap at 15 seconds — to avoid hitting Canva's rate limits (429 Too Many Requests).
  • Set expectations with users up front: the Canva Connect API provides asset browsing and export, not an embeddable design editor inside your FlutterFlow app.
  • Store access tokens and refresh tokens in Firestore (server-side), not in FlutterFlow app state or local storage — tokens must never leave the backend.
  • Request only the OAuth scopes your app actually needs during Canva integration registration — minimal scopes reduce the risk if credentials are ever compromised.
  • Implement a sequential export queue (one export at a time) rather than allowing parallel exports, to avoid rate limit errors when users request multiple designs in quick succession.
  • Cache the returned export download URLs for a short period (60 minutes) in Firestore to avoid triggering duplicate export jobs for the same design within a single session.
  • Verify the user's Canva plan level before surfacing brand kit features — some asset types require Canva Pro or Teams, and calling those endpoints with a free account returns 403 errors.

Alternatives

Frequently asked questions

Can I embed the Canva editor inside my FlutterFlow app so users can design in-app?

No — the Canva Connect API does not provide an embeddable editor. It's a data and export API for listing designs, browsing brand assets, and generating exports. If you want users to edit designs, you'd need to deep-link them to the Canva app or website from your FlutterFlow app using a url_launcher Custom Action. The Connect API is designed for surfacing and exporting Canva content, not editing it in third-party apps.

Do I need a Canva Pro account to use the Connect API?

You need any paid Canva plan (Pro, Teams, or Enterprise) to access some Connect API features — particularly brand kits, folder management, and certain asset types. Basic design listing and exporting may work with a free account, but check the Canva developer documentation for current plan requirements on each endpoint. Canva's API access policy can change, so verify before building features that depend on Pro-only endpoints.

How long does a Canva export take to complete?

Export times vary by design complexity and format. Simple single-page PNG exports typically complete in 5-15 seconds. Multi-page PDF exports can take 20-60 seconds for complex designs. The proxy's polling loop should handle this range without timing out — use a maximum of 10-15 polling attempts with exponential backoff starting at 2 seconds. Surface a loading indicator in the FlutterFlow UI while the export is in progress.

What happens when a Canva access token expires? Do users need to re-authorize?

Canva OAuth access tokens expire after a period defined by the token's expires_in value. Your Firebase Cloud Function proxy should automatically use the stored refresh token to obtain a new access token before it expires — this is the standard OAuth token refresh pattern. If a refresh token is revoked (the user disconnects the app in Canva settings), your proxy will receive a 401 error and should prompt the user to re-authorize by returning an authentication error to FlutterFlow, which then triggers the OAuth flow again.

Can I use the Canva Connect API to auto-generate designs with user data?

The Canva Connect API does support design content modification via the autofill API (populating design templates with data) — this is an advanced feature available for specific integration types. It requires a design template created with the Canva bulk creation workflow. Check the Canva developer documentation for the autofill endpoints and requirements, as this capability is distinct from the basic asset listing and export flow described in this guide.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire FlutterFlow integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.