Canvas meets Notion for always current assignments
Your assignments live in Canvas, but your life lives somewhere else. So you end up copying due dates into Notion, checking Canvas again “just in case,” and still getting surprised by a changed deadline.
This Canvas Notion sync hits students hardest, honestly. But academic coaches and parents supporting teens feel the same chaos when work gets missed because the list was stale.
This workflow keeps Canvas and a Notion database aligned, automatically. You’ll see what it does, what you need, and how it saves you from constant double-checking.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Canvas meets Notion for always current assignments
flowchart LR
subgraph sg0["Schedule Flow"]
direction LR
n0["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/compare.svg' width='40' height='40' /></div><br/>Compare Datasets"]
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Get Item Data"]
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/markdown.dark.svg' width='40' height='40' /></div><br/>Markdown"]
n3@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Isn't locked", pos: "b", h: 48 }
n4@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Is Canvas Complete?", pos: "b", h: 48 }
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Notion"]
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Planner"]
n7@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Notion is complete", pos: "b", h: 48 }
n8@{ icon: "mdi:play-circle", form: "rounded", label: "Schedule Trigger", pos: "b", h: 48 }
n9@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Not an event", pos: "b", h: 48 }
n10["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Update Override"]
n11@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Override Exists", pos: "b", h: 48 }
n12["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>New Override"]
n13["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Merge Item Data"]
n14["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Merge OpenAI Ranking"]
n15["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Add to Notion"]
n16["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Mark Notion as complete"]
n17@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Notion isn't started", pos: "b", h: 48 }
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Update Due Date"]
n19["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>OpenAI Categorization"]
n20["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Webhook"]
n21@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Different Due Dates", pos: "b", h: 48 }
n5 --> n0
n6 --> n0
n20 --> n6
n20 --> n5
n2 --> n13
n3 --> n14
n3 --> n19
n9 --> n1
n9 --> n13
n1 --> n2
n13 --> n3
n11 --> n10
n11 --> n12
n0 --> n9
n0 --> n4
n0 --> n21
n8 --> n6
n8 --> n5
n7 --> n11
n21 --> n18
n4 --> n17
n4 --> n7
n14 --> n15
n17 --> n16
n19 --> n14
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n8 trigger
class n3,n4,n7,n9,n11,n17,n21 decision
class n5,n15,n16,n18 database
class n1,n6,n10,n12,n19,n20 api
classDef customIcon fill:none,stroke:none
class n0,n1,n2,n5,n6,n10,n12,n13,n14,n15,n16,n18,n19,n20 customIcon
The Problem: Your “real” task list is always wrong
Canvas is the source of truth for assignments, due dates, and submission status. But most people don’t plan their day inside Canvas. They plan in Notion, a notebook, a calendar app, or a mix of all three. That’s where things crack. A due date gets updated, you don’t notice, and now your week is off. Or you submit an assignment but forget to mark it done in Notion, so it keeps nagging you. Multiply that by 5 classes and a busy week and you’re spending real time just maintaining your list.
It adds up fast. Here’s where it breaks down in real life.
- Copying assignments into Notion takes about 20 minutes per week, then you still have to maintain them.
- Canvas due dates change, and your Notion list silently becomes untrustworthy.
- Completion gets out of sync, so you either redo checks or miss work you thought you finished.
- Without consistent fields (class, link, ID), you can’t sort or prioritize cleanly across courses.
The Solution: Two-way Canvas → Notion assignment syncing
This workflow pulls your current planner items and assignment details from Canvas, compares them to what’s already in your Notion database, then updates Notion so it matches reality. New assignments become new Notion rows with the right fields filled in (class name, due date, link, and a stable ID for syncing). Existing items get adjusted when due dates change. And when Canvas shows an assignment has been submitted, the workflow marks it Completed in Notion too, so your task list stops yelling at you.
By default, it runs every 2 hours during the school day (about 7 times a day), which means changes show up without you thinking about them. You can also trigger a manual refresh via a webhook, which is handy when you just got a new assignment and want it in Notion immediately.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you’re taking 5 classes and you average 12 active assignments at a time. Manually, most people spend about 3 minutes per assignment each week re-checking due dates, links, and completion, which is roughly 35 minutes. Add another 10 minutes to create new tasks and clean up duplicates. With this workflow, the schedule runs 7 times a day and your “work” is basically zero minutes unless something looks off. You might do a 2-minute manual refresh via webhook after a big lecture, then move on.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Canvas LMS API token to read assignments and submissions
- Notion integration token to create and update database rows
- OpenAI API key (get it from the OpenAI API dashboard) for effort estimates, or disable that node
Skill level: Intermediate. You’ll copy IDs/tokens, update a few URLs to match your school’s Canvas domain, and map Notion properties once.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
It starts on a schedule (or on demand). The workflow runs every 2 hours during the school day by default, and you can also trigger it with an incoming webhook when you want an immediate refresh.
Canvas and Notion records get pulled into the same “view.” n8n fetches planner items and assignment details from Canvas via HTTP requests, then retrieves your existing Notion tasks from the database you chose.
The workflow compares what exists vs. what’s new. It aligns the two record sets using the assignment ID, filters out non-assignment events, and detects changes like “due date moved” or “now submitted.” If you enable it, the AI step also produces a rough effort estimate so your Notion view can show XS to XL without you guessing every time.
Notion becomes the clean output. Missing items get created, due dates get adjusted, and completed work is marked completed so your database stays current without manual maintenance.
You can easily modify the schedule window to match your own routine, or change the Notion fields that get written, based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Webhook Trigger
Set up the webhook path that can manually refresh the sync and trigger the data pull from Canvas and Notion.
- Add and open Incoming Webhook Trigger.
- Set Path to
refresh. - Confirm that Incoming Webhook Trigger outputs to both Fetch Planner Items and Retrieve Notion Tasks in parallel.
Step 2: Configure the Scheduled Automation Trigger
Define the scheduled sync timing so the workflow runs without manual input.
- Open Scheduled Automation Trigger.
- Set the Cron Expression to
2 0,9,11,13,15,17,20 * * *. - Verify that Scheduled Automation Trigger outputs to both Fetch Planner Items and Retrieve Notion Tasks in parallel.
Step 3: Connect Canvas and Notion Data Sources
Pull Planner items from Canvas and tasks from Notion, then align them for comparison.
- Open Fetch Planner Items and set URL to
=https://canvas.wisc.edu/api/v1/planner/items. - In Fetch Planner Items, set query parameters: start_date to
={{ new Date(Date.now() - 7*8.64e7).toISOString() }}, end_date to={{ new Date(Date.now() + (21*8.64e7)).toISOString() }}, and per_page to75. - Credential Required: Connect your
httpHeaderAuthcredentials in Fetch Planner Items. - Open Retrieve Notion Tasks and set the database to your Tasks database (
[YOUR_ID]). - In Retrieve Notion Tasks, set the filter to Last edited time after
={{ new Date(new Date().setMonth((new Date()).getMonth() - 1)).toISOString() }}. - Credential Required: Connect your
notionApicredentials in Retrieve Notion Tasks. - Open Align Record Sets, set Fuzzy Compare to enabled, and set Merge By Fields to
plannable_id(input A) andproperty_id(input B). - Confirm that Align Record Sets outputs to Exclude Events Filter, Canvas Completion Check, and Detect Due Date Changes.
[YOUR_ID] placeholders in Notion database selectors before running the workflow.Step 4: Enrich Items and Run AI Estimation
Filter non-assignment items, fetch assignment details, convert content to markdown, and estimate effort using OpenAI.
- Open Exclude Events Filter and set conditions so plannable_type is not equal to
calendar_eventand not equal toannouncement. - Confirm that Exclude Events Filter outputs to both Fetch Item Details and Combine Item Payloads in parallel.
- In Fetch Item Details, set URL to
=https://canvas.wisc.edu/api/v1{{ $json.html_url }}. - Credential Required: Connect your
httpHeaderAuthcredentials in Fetch Item Details. - In Convert to Markdown, set HTML to
={{ $json.description || $json.message || "" }}and Destination Key tomarkdown. - In Combine Item Payloads, set Mode to
combineand Combination Mode tomergeByPosition. - Open Unlocked Filter and configure the OR conditions:
={{ $json.lock_info.unlock_at || $json.unlock_at }}is before={{ new Date().toISOString() }}, or={{ $json.lock_info }}does not exist. - Confirm that Unlocked Filter outputs to both Merge AI Estimate and AI Effort Estimator in parallel.
- In AI Effort Estimator, keep URL set to
https://api.openai.com/v1/chat/completionsand Model set togpt-4o. - Credential Required: Connect your
openAiApicredentials in AI Effort Estimator. - In Merge AI Estimate, set Mode to
combineand Combination Mode tomergeByPosition.
Step 5: Configure Notion Outputs
Create new Notion task entries and update existing task statuses and due dates.
- Open Create Notion Entry and set Title to
={{ $json.plannable.title }}. - In Create Notion Entry, set block content to
={{ $json.markdown.slice(0,1900) }}. - Map properties in Create Notion Entry: ID to
={{ $json.plannable_id.toString() }}, Due Date to={{ $json.plannable.due_at }}{{ $json.plannable.todo_date }}, Class to={{ $json.context_name.replace(/:.*/, "") }}, Link to=https://canvas.wisc.edu{{ $json.html_url }}, Priority to=Should Do, and Estimate to={{ $json.choices[0].message.content.parseJson().estimate }}. - Credential Required: Connect your
notionApicredentials in Create Notion Entry. - Open Set Notion Completed and set Page ID to
={{ $json.different.id.inputB }}, then set Status toCompleted. - Credential Required: Connect your
notionApicredentials in Set Notion Completed. - Open Adjust Due Date and set Page ID to
={{ $json.different.id.inputB }}and Due Date to={{ $json.different.plannable.inputA.due_at }}{{ $json.different.plannable.inputA.todo_date }}. - Credential Required: Connect your
notionApicredentials in Adjust Due Date.
Step 6: Configure Status and Override Sync Logic
Keep Canvas completion status and Notion task status aligned, and update planner overrides when tasks are completed in Notion.
- In Canvas Completion Check, keep the OR conditions:
={{ $json.different.planner_override.inputA.marked_complete }}is true or={{ $json.different.submissions.inputA.submitted }}is true. - In Notion Status Completed, set the condition to
={{ $json.different.property_status.inputB }}equalsCompleted. - In Notion Status Not Started, set the condition to
={{ $json.different.property_status.inputB }}equalsNot Started. - In Detect Due Date Changes, compare
={{ DateTime.fromISO($json.different.plannable.inputA.due_at).toISODate() }}to={{ $json.different.property_due_date.inputB.start }}and keep Loose Type Validation enabled. - In Override Presence Check, verify that
={{ $json.different.planner_override }}exists. - In Modify Planner Override, set URL to
=https://canvas.wisc.edu/api/v1/planner/overrides/{{ $json.different.planner_override ? $json.different.planner_override.inputA.id : ""}}and keep Method asPUT. - In Create Planner Override, set URL to
=https://canvas.wisc.edu/api/v1/planner/overridesand keep Method asPOST. - Credential Required: Connect your
httpHeaderAuthcredentials in both Modify Planner Override and Create Planner Override.
[YOUR_ID] in the JSON body of Modify Planner Override and Create Planner Override or Canvas will reject the request.Step 7: Test and Activate Your Workflow
Validate that the sync runs end-to-end, then enable automated execution.
- Click Execute Workflow and trigger Incoming Webhook Trigger with a test call to
/webhook/refresh. - Check that Fetch Planner Items and Retrieve Notion Tasks both execute, then confirm Align Record Sets produces matched and different items.
- Verify that Create Notion Entry creates new tasks, Set Notion Completed marks completed items, and Adjust Due Date updates dates when changes are detected.
- Confirm that Modify Planner Override or Create Planner Override runs when Notion items are completed.
- When satisfied, toggle the workflow to Active so Scheduled Automation Trigger runs on the cron schedule.
Common Gotchas
- Canvas credentials can expire or need specific permissions. If things break, check your Canvas “New Access Token” page in account settings first and confirm the token still works.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Frequently Asked Questions
About 45 minutes if your Canvas and Notion tokens are ready.
No. You will paste API tokens and tweak a few fields. The hardest part is usually finding the right Notion database ID and Canvas domain.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API costs if you keep AI effort estimation enabled (usually a few cents for lots of assignments).
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, but you must map your database properties to match what the workflow writes. Most people customize the Notion “Create Notion Entry,” “Adjust Due Date,” and “Set Notion Completed” steps, then update field names like Status, Due Date, Class, and Link. If you don’t want AI estimates, simply disable the AI Effort Estimator and the Merge AI Estimate step. The sync still works fine without it.
Usually it’s an expired or revoked Canvas access token, or the Canvas URL in the HTTP Request nodes still points to the example domain instead of your institution’s domain. Regenerate the token in Canvas account settings, update it in n8n, then re-check the base URL on the Canvas HTTP requests. If it fails only on busy days, rate limiting can also be the culprit, so spacing requests slightly can help.
For most students, it’s effectively unlimited because you’re syncing dozens, not thousands.
Often, yes. Canvas syncing tends to need multiple HTTP calls, comparisons, and branching logic (for new items vs updated items vs completed items), and n8n handles that without turning every little branch into an extra paid step. Self-hosting also matters here because scheduled syncing 7 times a day adds up quickly on per-task pricing. Zapier or Make can still work if you only need a one-way “create new assignment rows” flow and never want to update or complete existing items. If you’re unsure, Talk to an automation expert and you’ll get a straight answer.
Once this is running, your Notion assignment list stops being “another thing to maintain.” It just stays current, and you get your attention back.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.