Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Bulk-create Canva designs from tabular data using a brand template with autofill fields, producing one design per row. Use when users say \"bulk create designs from this CSV\", \"generate one design per row\", \"create a design for each product\", \"batch generate from a template\", or \"autofill a template from a spreadsheet\". Accepts any tabular data source — uploaded files, pasted tables, JSON
.claude/skills/kunanonj-cursor-plugin-canva-bulk-create/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 25% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 67% | 0% |
| case-03 | ✗→✓ | ▲ Improved | -33% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 73% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 38% | 0% |
Create one Canva design per row of data by autofilling a brand template with data tags.
Accept data in any form the user provides and extract a list of rows with named columns:
If no data has been provided, ask the user to share it in whatever format is convenient for them.
Once parsed, show the user:
If the user hasn't specified a template, search for autofill-capable ones:
Canva:search-brand-templates dataset=non_emptyShow the results and ask the user to pick one. If they already named or described a template, search with that query.
Canva:get-brand-template-dataset template_id=<selected_id>This returns the field names and types (text, image, chart) that the template expects.
Present a mapping table to the user:
| Template Field | Type | Matched CSV Column | Notes | |---|---|---|---| | product_name | text | Product Name | auto-matched | | price | text | Price | auto-matched | | hero_image | image | (none) | no match — image fields need asset IDs |
Matching rules:
Confirm the mapping with the user before proceeding, especially if there are unmapped fields or ambiguous matches.
There are two ways a CSV can supply images for image-type template fields:
Pattern A — CSV has a Canva asset ID column (e.g. image_asset_id): Use the asset ID value directly in the autofill-design call:
json{ "image": { "type": "image", "asset_id": "<value from CSV column>" } }
Pattern B — CSV has an image URL column (e.g. image_url): URLs cannot be passed directly to autofill-design. Upload each URL to Canva first using Canva:upload-asset-from-url, capture the returned asset ID, then use it in the autofill call. Do the upload immediately before creating that row's design so failures stay localised.
Pattern C — No image column in CSV: Ask the user whether to skip the image field (template default image stays) or abort. Skipping is safe — just omit the image key from the data payload entirely.
Loop through every CSV row and call Canva:autofill-design for each one. Call them sequentially, not all at once — the API may have rate limits and sequential calls are easier to debug.
For each row:
Canva:upload-asset-from-url to get a Canva asset ID.data payload from the confirmed field mapping:json{ "text_field_name": { "type": "text", "text": "<value from CSV>" }, "image_field_name": { "type": "image", "asset_id": "<asset ID>" } }
Canva:autofill-design with the template ID, data payload, and a descriptive title using the row number or a meaningful column value (e.g. "Bulk Design - Row 3 - <identifier>").Track results as you go:
Row 1 / 50: Created — <design_url>
Row 2 / 50: Created — <design_url>
Row 3 / 50: Failed — <error>After all rows are processed, summarise:
Offer to save a summary CSV with columns: row, status, design_url, error.
get-brand-template-dataset.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-05 | pass→pass | 9,332 | 5,393 | -42% | 1 | 1 | 0% | 1,778 | 2,312 | +30% | 0 | 0 | — |
case-06 | fail→fail | 8,708 | 5,038 | -42% | 1 | 1 | 0% | 1,621 | 2,146 | +32% | 0 | 0 | — |
case-07 | fail→pass | 9,671 | 4,877 | -50% | 1 | 1 | 0% | 1,711 | 2,135 | +25% | 0 | 0 | — |
case-08 | fail→pass | 6,704 | 4,416 | -34% | 1 | 1 | 0% | 1,205 | 2,012 | +67% | 0 | 0 | — |
case-01 | fail→fail | 9,966 | 6,898 | -31% | 1 | 1 | 0% | 1,972 | 1,778 | -10% | 0 | 0 | — |
case-02 | fail→fail | 7,827 | 10,198 | +30% | 1 | 1 | 0% | 1,478 | 2,860 | +94% | 0 | 0 | — |
case-03 | fail→pass | 12,617 | 3,026 | -76% | 1 | 1 | 0% | 2,726 | 1,824 | -33% | 0 | 0 | — |
case-04 | fail→pass | 6,464 | 3,751 | -42% | 1 | 1 | 0% | 1,128 | 1,955 | +73% | 0 | 0 | — |
case-09 | pass→pass | 6,864 | 4,542 | -34% | 1 | 1 | 0% | 1,290 | 2,012 | +56% | 0 | 0 | — |
case-10 | fail→pass | 8,781 | 4,574 | -48% | 1 | 1 | 0% | 1,515 | 2,098 | +38% | 0 | 0 | — |
case-11 | fail→pass | 4,892 | 3,866 | -21% | 1 | 1 | 0% | 854 | 1,979 | +132% | 0 | 0 | — |
case-12 | fail→pass | 13,493 | 4,108 | -70% | 1 | 1 | 0% | 2,302 | 1,990 | -14% | 0 | 0 | — |
case-13 | fail→pass | 8,970 | 3,627 | -60% | 1 | 1 | 0% | 1,579 | 1,875 | +19% | 0 | 0 | — |
case-14 | fail→fail | 10,056 | 2,197 | -78% | 1 | 1 | 0% | 1,863 | 1,625 | -13% | 0 | 0 | — |
case-15 | fail→pass | 6,664 | 3,278 | -51% | 1 | 1 | 0% | 1,248 | 1,922 | +54% | 0 | 0 | — |
case-16 | fail→pass | 9,098 | 1,679 | -82% | 1 | 1 | 0% | 1,909 | 1,578 | -17% | 0 | 0 | — |
case-17 | pass→pass | 4,859 | 2,486 | -49% | 1 | 1 | 0% | 942 | 1,695 | +80% | 0 | 0 | — |
case-18 | fail→pass | 9,566 | 2,821 | -71% | 1 | 1 | 0% | 1,892 | 1,839 | -3% | 0 | 0 | — |
case-19 | pass→pass | 5,095 | 3,105 | -39% | 1 | 1 | 0% | 1,020 | 1,720 | +69% | 0 | 0 | — |
case-20 | fail→pass | 5,225 | 2,509 | -52% | 1 | 1 | 0% | 976 | 1,687 | +73% | 0 | 0 | — |
case-21 | fail→pass | 8,080 | 3,531 | -56% | 1 | 1 | 0% | 1,541 | 1,853 | +20% | 0 | 0 | — |
case-22 | pass→pass | 8,642 | 5,626 | -35% | 1 | 1 | 0% | 1,721 | 2,405 | +40% | 0 | 0 | — |
case-23 | pass→pass | 8,284 | 10,084 | +22% | 1 | 1 | 0% | 1,759 | 2,927 | +66% | 0 | 0 | — |
case-24 | pass→pass | 11,404 | 5,668 | -50% | 1 | 1 | 0% | 2,203 | 2,128 | -3% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted, and 22 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +54 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.