FlowKit

Construire un RAG sur votre base de connaissances Notion avec n8n

Publié le 2 août 2026 · 6 min de lecture

Votre documentation d'équipe vit dans Notion : procédures, comptes rendus, fiches produit, décisions. Le problème n'est pas d'écrire, c'est de retrouver — la recherche native de Notion trouve des mots-clés, pas des réponses. Le RAG (retrieval-augmented generation) comble exactement cet écart : l'approche, formalisée par Lewis et al. dans un article présenté à NeurIPS en 2020 (« Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks », voir sur Google Scholar), consiste à récupérer les passages pertinents d'un corpus puis à les fournir au modèle au moment de répondre, ce qui améliore la factualité et permet de citer les sources. Voici comment construire ce pipeline avec n8n, de l'extraction des pages Notion jusqu'à la synchronisation incrémentale.

Architecture du pipeline

  1. Extraction : le node Notion liste les pages du périmètre choisi et récupère leurs blocs.
  2. Conversion : les blocs JSON de l'API Notion sont transformés en markdown exploitable.
  3. Chunking : le texte est découpé en s'appuyant sur la structure des pages (titres, sections).
  4. Vectorisation : chaque chunk est transformé en embedding et inséré dans Supabase pgvector avec ses métadonnées (page, URL, date).
  5. Synchronisation : un workflow planifié détecte les pages modifiées via last_edited_time et réindexe uniquement celles-là.

Si vous avez lu notre guide sur le RAG avec Google Drive, la logique est identique — seule la source change, et avec elle les pièges spécifiques : blocs imbriqués, bases de données, limites de débit.

Étape 1 : extraire les pages avec le node Notion

Prérequis : une intégration Notion avec les pages cibles partagées explicitement — notre guide pour connecter Notion à n8n détaille la création du token et le partage. Ne partagez que le périmètre à indexer : c'est votre premier filtre de pertinence et de confidentialité.

Première distinction structurante : pages et bases de données ne s'extraient pas pareil.

  • Une base de données Notion se requête avec l'opération de type Database Page → Get Many : chaque ligne est une page, avec ses propriétés (statut, tags, dates) qui feront d'excellentes métadonnées.
  • Une page libre se lit via ses blocs : l'opération Block → Get Many (ou l'endpoint blocks/{id}/children) renvoie les blocs enfants, paginés par lots de 100 avec un curseur next_cursor tant que has_more vaut true.

Deuxième subtilité : les blocs imbriqués. Un toggle, une liste à puces avec sous-éléments, une colonne ou un callout peuvent contenir des blocs enfants (has_children: true) que l'appel parent ne renvoie pas. Selon la version du node Notion, une option permet de récupérer aussi les blocs imbriqués ; sinon, il faut boucler récursivement sur chaque bloc marqué has_children. Si vous sautez cette étape, tout le contenu rangé dans des toggles — souvent l'essentiel d'une FAQ interne — disparaît silencieusement de votre index.

Étape 2 : convertir les blocs en markdown

L'API Notion ne renvoie pas du texte mais des objets JSON : chaque bloc a un type (paragraph, heading_2, bulleted_list_item, code, toggle…) et un tableau rich_text. Un node Code fait la conversion :

const md = items.map(({ json: b }) => {
  const text = (b[b.type]?.rich_text || [])
    .map(t => t.plain_text).join('');
  if (b.type === 'heading_1') return `# ${text}`;
  if (b.type === 'heading_2') return `## ${text}`;
  if (b.type === 'heading_3') return `### ${text}`;
  if (b.type === 'bulleted_list_item') return `- ${text}`;
  if (b.type === 'toggle') return `## ${text}`;
  return text;
}).join('\n\n');
return [{ json: { markdown: md } }];

Conserver les niveaux de titres n'est pas cosmétique : c'est ce qui rend possible le chunking structurel de l'étape suivante. Les bases de données rencontrées dans une page (blocs child_database) méritent un traitement à part : requêtez-les comme des bases et sérialisez chaque ligne en une phrase (« Client : Acme — Statut : signé — Montant : … ») plutôt que d'ignorer le bloc.

Étape 3 : un chunking qui suit la structure Notion

Notion vous offre ce que les PDF n'ont pas : une structure explicite. Exploitez-la — découpez prioritairement sur les frontières de heading_1 et heading_2, gardez le contenu d'un toggle attaché à son titre, et ne fusionnez jamais deux sections sans rapport dans un même chunk. Les règles générales (taille de 500 à 1 000 tokens, chevauchement, découpe de secours sur les paragraphes) sont détaillées dans notre guide du chunking de documents pour le RAG.

Ce choix est aussi économiquement rationnel : une étude de Qu, Tu et Bao publiée en 2024 (« Is Semantic Chunking Worth the Computational Cost? », voir sur Google Scholar) montre que le chunking sémantique coûteux (calculé par embeddings) n'apporte pas de gain constant par rapport à des découpes plus simples. Avec Notion, la structure sémantique est déjà là, gratuite, dans les headings : autant s'en servir.

Étape 4 : embeddings, pgvector et métadonnées

Le node Supabase Vector Store (mode insert), branché à un modèle d'embeddings, vectorise et insère chaque chunk — la mise en place complète de la table documents et de la fonction de similarité est décrite dans notre guide RAG avec n8n et Supabase, et le choix du modèle dans notre comparatif des modèles d'embeddings.

Le point qui fera la différence à l'usage : les métadonnées de chaque chunk.

{
  "notion_page_id": "{{ $json.id }}",
  "title": "{{ $json.name }}",
  "url": "{{ $json.url }}",
  "last_edited": "{{ $json.last_edited_time }}",
  "section": "{{ $json.currentHeading }}"
}

L'url (renvoyée par l'API pour chaque page) permet au chatbot de citer la page Notion source avec un lien cliquable ; le notion_page_id rend possible la suppression ciblée à la resynchronisation ; last_edited sert d'audit.

Étape 5 : synchronisation incrémentale avec last_edited_time

Réindexer tout l'espace chaque nuit gaspille des appels API et des embeddings. La bonne approche : un Schedule Trigger qui interroge les pages modifiées depuis la dernière exécution. Sur une base de données Notion, le filtre s'écrit directement :

{
  "filter": {
    "timestamp": "last_edited_time",
    "last_edited_time": { "on_or_after": "{{ $json.lastSyncedAt }}" }
  }
}

Deux précautions d'expérience : last_edited_time est arrondi à la minute par Notion, donc prévoyez un léger chevauchement de fenêtre (et une réindexation idempotente) plutôt qu'une comparaison stricte ; et pour chaque page modifiée, appliquez la séquence delete puis insert — supprimez d'abord tous les vecteurs portant son notion_page_id, puis réinsérez les nouveaux chunks. Sans cela, les versions s'accumulent et le RAG cite des contenus obsolètes ; le pattern complet (suppressions de pages incluses) est détaillé dans notre guide sur la mise à jour d'un index RAG. Si vous préférez partir d'une base prête à l'emploi, notre workflow de synchronisation Notion vers base vectorielle implémente exactement ce mécanisme.

Le piège transversal : les limites de débit

L'API Notion tolère en moyenne de l'ordre de trois requêtes par seconde ; au-delà, elle répond 429 avec un en-tête Retry-After. Or votre pipeline multiplie les appels : une page = un appel pour les propriétés, un ou plusieurs pour les blocs, plus la récursion sur les blocs imbriqués. Trois parades : activez le retry on fail avec délai sur les nodes Notion, traitez les pages en séquence (Loop Over Items) plutôt qu'en parallèle, et espacez les lots avec un node Wait. L'indexation initiale d'un gros espace peut prendre du temps — c'est normal et sans importance, puisque l'incrémental prend le relais ensuite.

Interroger : agent, citations, et la suite

Côté interrogation, c'est un RAG standard : un AI Agent (ou une chaîne question-réponse) équipé du Vector Store en outil, avec un prompt qui impose de citer les pages sources via les métadonnées. Si les utilisateurs cherchent souvent des termes exacts — noms de clients, références produit —, ajoutez une recherche hybride vecteurs + mots-clés, le raffinement au meilleur rapport effort/impact. Le Pack Assistant RAG regroupe cette moitié aval prête à brancher : chatbot avec citations, API question-réponse et la synchronisation Notion de cet article.

En résumé

  • Extraction : distinguez bases de données (requêtes filtrables) et pages (blocs paginés par 100), et récupérez récursivement les blocs imbriqués (has_children) — sinon les toggles disparaissent de l'index.
  • Conversion : transformez les blocs JSON en markdown en préservant les headings, qui guideront le chunking.
  • Chunking : suivez la structure Notion (sections, toggles) plutôt qu'un découpage sémantique coûteux.
  • Métadonnées : notion_page_id, url, last_edited — pour les citations et la resynchronisation propre.
  • Sync incrémentale : filtre sur last_edited_time (arrondi à la minute), séquence delete puis insert.
  • Débit : environ trois requêtes par seconde en moyenne ; retry, séquentiel et node Wait.

FAQ

Questions fréquentes

Combien de temps prend l'indexation initiale d'un espace Notion ?

Cela dépend surtout des limites de débit de l'API Notion, autour de trois requêtes par seconde en moyenne : chaque page demande plusieurs appels (blocs paginés par 100, blocs imbriqués). Pour quelques centaines de pages, comptez de plusieurs minutes à une heure. C'est un traitement ponctuel : ensuite, la synchronisation incrémentale ne touche que les pages modifiées.

Faut-il indexer tout l'espace Notion ou seulement certaines pages ?

Restreignez le périmètre : partagez uniquement les pages ou bases de données utiles avec l'intégration Notion, plutôt que l'espace entier. Vous gagnez en pertinence (moins de bruit dans le retrieval), en vitesse d'indexation, et vous évitez d'exposer des contenus sensibles à tous les utilisateurs du chatbot.

Peut-on utiliser une autre base vectorielle que Supabase pgvector ?

Oui, le pipeline est identique avec Qdrant, Pinecone ou Weaviate : seul le node Vector Store change. Supabase pgvector reste un bon choix par défaut si vous voulez gérer vecteurs et métadonnées en SQL standard, notamment pour la suppression ciblée des chunks d'une page lors de la resynchronisation.

Comment le chatbot peut-il citer la page Notion d'origine dans ses réponses ?

En stockant l'URL de la page dans les métadonnées de chaque chunk au moment de l'indexation. À la génération, le prompt demande au modèle de mentionner ses sources, et vous reconstruisez des liens cliquables vers Notion à partir des métadonnées des chunks récupérés. C'est indispensable pour que les utilisateurs puissent vérifier une réponse.

Bundle FlowKit Complet

269 €