Si eres estudiante, probablemente vives entre dos apps: Canvas (donde tus profesores publican tareas, quizzes y fechas límite) y Notion (donde realmente organizas tu vida). El problema es que son mundos separados — cada tarea nueva en Canvas significa copiarla manualmente a tu Notion si quieres verla junto a tus demás pendientes.
Esta guía es el paso a paso para armar esa conexión tú mismo: qué se puede lograr de verdad, qué no hay que esperar, y cómo dejarlo corriendo solo en menos de 20 minutos. La escribí armando mi propio sync como Notion Campus Leader, así que todo lo que sigue está probado en un caso real.
Módulo HTTP llama a la API de Canvas → Iterator → módulo nativo de Notion crea/actualiza páginas
Media (mapeo visual, pero limitado por la UI)
Buena
Baja
Script + GitHub Actions
Un script en Python llama a la Canvas Planner API y hace upsert vía Notion API, corriendo en un cron gratuito de GitHub
Total (controlas cada campo, formato y regla)
Excelente
Media (pero un solo setup, reutilizable)
La recomendación principal es el segundo camino. No por difícil, sino por lo que te da a ti:
Tu token de Canvas nunca sale de tu cuenta. Corres tu propia copia del script en tu propio GitHub, con tus llaves. No hay un servidor central con tus credenciales — ni mío ni de nadie. (Centralizar tokens ajenos, además, suele ir contra la política de la institución.)
Es gratis y no se te acaba.Make.com te da 1,000 operaciones al mes en el plan gratis; con un sync corriendo cada pocas horas las consumes rápido. El repo de GitHub lo haces fork una vez y es tuyo, sin cuota que se agote.
Controlas cómo se ve todo: nombres de propiedades, iconos por tipo de tarea, relación con una base de Cursos, un campo de "días para la entrega"… lo que quieras.
Esto es lo más importante del plan: prometer de más es la forma más rápida de que un proyecto de automatización se sienta "roto".
✅ En el alcance (v1):
Sincronización de un solo sentido: Canvas → Notion. Notion nunca escribe de vuelta a Canvas.
Se sincronizan tareas, quizzes, discusiones con fecha de entrega y eventos de calendario, usando el endpoint Planner de Canvas (el mismo que alimenta el dashboard "Lista" de Canvas).
Una base de datos en Notion por estudiante, con upsert automático (no se duplican tarjetas en cada corrida).
Corre sola cada cierto tiempo (por ejemplo cada 3 horas) vía GitHub Actions — no necesitas dejar tu computadora prendida.
❌ Fuera de alcance (v1) — y por qué:
Sync bidireccional real: marcar "Done" en Notion no entrega la tarea en Canvas. Entregar una tarea implica subir un archivo o responder un quiz; eso no se puede ni se debe automatizar por seguridad académica.
Tiempo real / webhooks: Canvas solo expone eventos en tiempo real (Live Events) a nivel institucional/admin — un estudiante no tiene ese acceso. Por eso el sync es por polling (revisa cada X horas), no instantáneo.
Un servidor central que lo haga por ti: no lo hay, a propósito. Tú corres tu propia copia con tus llaves, y tu token de Canvas nunca queda en manos de nadie más.
Notas/calificaciones: técnicamente la API lo permite, pero es información sensible — queda como posible v2, opcional y explícito.
Cuenta de Canvas activa (tu instancia institucional, ej. tuescuela.instructure.com)
Cuenta de Notion (gratis)
Cuenta de GitHub (gratis) — para que el script corra automáticamente sin tu computadora
Opcional: Claude, Codex o Cursor conectado a Notion, para usar los prompts de cada paso (Paso 0)
#Paso 0 — Conecta tu agente de IA a Notion (opcional)
Si usas Claude, Codex o Cursor, conéctalo primero al MCP oficial de Notion. Con eso cada paso de esta guía trae un prompt listo para copiar, y el agente hace la parte repetitiva: crear la base con sus 7 propiedades, buscar el ID, armar el repo y revisar que no haya duplicados.
Los pasos que tocan tokens (1 y 3) siguen siendo manuales. Es a propósito.
Después abre Claude Code, corre /mcp, elige Notion y completa el login en el navegador. El --scope user hace que Notion esté disponible en cualquier carpeta, incluida la del repo que vas a crear en el Paso 5.
Crea una base de datos nueva (full-page) llamada, por ejemplo, Canvas Sync, con estas propiedades:
Propiedad
Tipo
Uso
Name
Title
Nombre de la tarea/evento
Course
Select
Materia a la que pertenece
Type
Select
Assignment / Quiz / Discussion / Event
Due Date
Date
Fecha límite
Status
Status
Not started / In progress / Done, las opciones por defecto de Notion (manual, solo vive en Notion)
Canvas Link
URL
Link directo al ítem en Canvas
Canvas ID
Rich text
ID único de Canvas — clave para evitar duplicados (puedes ocultarla de la vista)
Prompt para tu agente
plain text
Usa el MCP de Notion para crear una base de datos full-page llamada "Canvas Sync". Si no sabes dónde ponerla, créala como página privada y dime dónde quedó.
Propiedades exactas. Respeta nombres y mayúsculas, el script de sincronización depende de ellos:
- Name: Title
- Course: Select, sin opciones (el script las crea solo)
- Type: Select con opciones Assignment, Quiz, Discussion, Event
- Due Date: Date
- Status: Status con las opciones por defecto (Not started, In progress, Done)
- Canvas Link: URL
- Canvas ID: Text
Después crea tres vistas: una tabla ordenada por Due Date ascendente, un board agrupado por Course y un calendario por Due Date. Si puedes, oculta Canvas ID en la tabla.
No crees filas de prueba. Al terminar muéstrame el esquema final y el link a la base.
Copia el Internal Integration Secret (empieza con secret_ o ntn_).
Abre tu base de datos Canvas Sync, ve a ··· → Connections → conecta tu nueva integración. Sin este paso, la API no podrá escribir ahí aunque tengas el token.
Copia la URL de tu base de datos. El ID es el bloque de 32 caracteres antes del ?:
javascript
https://www.notion.so/tuworkspace/1a2b3c4d5e6f7890abcd1234ef567890?v=... \_______________________________/ Database ID
Prompt para tu agente
plain text
Usa el MCP de Notion para buscar mi base de datos "Canvas Sync" y dame su Database ID: los 32 caracteres del ID de la base, sin guiones.
Necesito el ID de la base (database), no el del data source (collection://...). Mi script resuelve el data source solo a partir del database ID.
Si hay más de una base con ese nombre, lístalas con su ubicación y pregúntame cuál es.
El script llama al endpoint Planner de Canvas (agrupa tareas, quizzes y eventos en una sola respuesta) y hace upsert en Notion usando el Canvas ID como llave de deduplicación.
Prompt para tu agente (Claude Code, Codex o Cursor)
plain text
Quiero armar un repo para sincronizar Canvas con Notion siguiendo esta guía: https://notion.santimh.dev/posts/canvas-notion-parte-1-guia-de-sincronizacion
En una carpeta nueva llamada canvas-notion-sync:
1. Crea sync.py con el script del Paso 5 de la guía, tal cual. Si no puedes abrir el link, pídeme que te pegue el script. No lo reescribas de memoria.
2. Crea requirements.txt con requests y notion-client>=3.0,<4
3. Crea un .gitignore que ignore .env, __pycache__/ y .venv/
4. Crea .env.example con CANVAS_DOMAIN, CANVAS_TOKEN, NOTION_TOKEN y NOTION_DATABASE_ID vacíos.
Reglas:
- Nunca escribas un token real en ningún archivo. Las credenciales solo se leen de variables de entorno.
- Usa el MCP de Notion para leer el esquema de mi base "Canvas Sync". Si algún nombre de propiedad no coincide con el script, ajusta upsert_item y dime qué cambiaste.
- No corras el script todavía.
Crea un repo (o haz fork de la plantilla), pon el script en sync.py y un requirements.txt con requests y notion-client>=3.0 (fija la versión mayor para evitar romper con futuros cambios de API). Luego ve a Settings → Secrets and variables → Actions y agrega:
CANVAS_DOMAIN
CANVAS_TOKEN
NOTION_TOKEN
NOTION_DATABASE_ID
Así el token nunca queda expuesto en el código ni en el historial de git.
Prompt para tu agente (Claude Code, Codex o Cursor)
plain text
Usa la CLI de GitHub (gh) para publicar este repo y configurar los secrets de Actions.
1. Verifica que gh esté instalado y autenticado con gh auth status. Si no lo está, dime qué correr y detente.
2. Haz git init, commit de los archivos y crea un repo privado llamado canvas-notion-sync con gh repo create. Antes del commit confirma que .env no está en staging.
3. Configura tú estos dos secrets, que no son sensibles:
gh secret set CANVAS_DOMAIN --body "TUESCUELA.instructure.com"
gh secret set NOTION_DATABASE_ID --body "TU_DATABASE_ID"
4. Para CANVAS_TOKEN y NOTION_TOKEN no me pidas los valores. Solo dame estos comandos para que yo los corra en mi propia terminal, donde gh me pide el valor de forma oculta:
gh secret set CANVAS_TOKEN
gh secret set NOTION_TOKEN
5. Cuando te avise que ya los puse, corre gh secret list y confirma que están los cuatro.
name: Sync Canvas to Notionon:schedule: - cron: "0 */3 * * *"# cada 3 horasworkflow_dispatch: {} # botón para correrlo manualmentejobs:sync:runs-on: ubuntu-lateststeps:
Prompt para tu agente (Claude Code, Codex o Cursor)
plain text
Crea el archivo .github/workflows/sync.yml con el workflow del Paso 7 de esta guía: https://notion.santimh.dev/posts/canvas-notion-parte-1-guia-de-sincronizacion
Tiene que:
- Correr cada 3 horas (cron "0 */3 * * *") y tener workflow_dispatch para correrlo a mano.
- Usar Python 3.12, instalar requirements.txt y correr python sync.py.
- Pasar CANVAS_DOMAIN, CANVAS_TOKEN, NOTION_TOKEN y NOTION_DATABASE_ID desde los secrets del repo.
Haz commit y push a main. No agregues otros pasos ni cambies el cron sin preguntarme.
Ve a la pestaña Actions de tu repo y corre el workflow manualmente (workflow_dispatch).
Revisa la base de datos en Notion — deberías ver tus tareas y eventos aparecer.
Vuelve a correrlo: si el upsert funciona bien, no deberían aparecer duplicados, solo actualizaciones.
Prompt para tu agente (Claude Code, Codex o Cursor)
plain text
Valida mi sync de Canvas a Notion de punta a punta:
1. Corre el workflow a mano con gh workflow run sync.yml y sigue la corrida con gh run watch. Si falla, lee el log con gh run view --log-failed, explícame el error y propón el fix sin aplicarlo.
2. Si pasa, usa el MCP de Notion para consultar la base "Canvas Sync" y dime cuántas filas hay en total, por Course y por Type.
3. Corre el workflow otra vez y vuelve a consultar. Confirma que el total no cambió y que ningún Canvas ID aparece dos veces. Si hay duplicados, lístalos.
Done: Canvas token generado
Done: Base de datos de Notion creada y conectada a la integración
Done: Secrets configurados en GitHub
Done: Primera corrida manual exitosa sin duplicados
Si prefieres no tocar código, esta es la versión más simple que de verdad funciona:
Trigger: módulo Schedule (cada X horas).
HTTP → Make a request: GET https://TUDOMINIO.instructure.com/api/v1/planner/items con header Authorization: Bearer TU_TOKEN.
Iterator: recorre el array que devuelve Canvas.
Notion → Search Objects: busca si ya existe una página con ese Canvas ID.
Router: si existe, Update a Database Item; si no, Create a Database Item.
Es el mismo esquema de datos del Paso 2. El límite real es la cuota gratuita de Make (1,000 operaciones/mes): alcanza para probar el concepto, pero con el sync corriendo seguido la agotas en pocas semanas.
#¿Eres Campus Leader y quieres llevarlo a tu campus?
Si además de usarlo tú quieres que lo use más gente, el resto ya casi está hecho:
Publica el repo de GitHub como template público, con un README que sea este mismo paso a paso.
Duplica la base de datos del Paso 2 como plantilla de Notion que cualquiera pueda "Duplicate" a su workspace.
Un workshop de 30 min donde cada quien genera su propio token de Canvas y su propia integración — nunca credenciales compartidas.
Cada persona termina con su copia independiente: tú no administras nada de nadie.
Relación con una base de datos de Cursos para ver GPA/progreso agregado.
Sync opcional de calificaciones (con warning explícito de privacidad).
Auto-archivar en Notion los ítems ya vencidos y completados.
Resumen diario enviado a Discord/Slack del campus.
Escribí esto resolviendo, para mí, un problema que casi todos tenemos: vivir entre Canvas y Notion sin que se hablen. Si lo armas y algo no te cuadra, escríbeme.
Written by Santiago Merino
Fullstack developer in El Salvador, building fast, accessible web apps.