GuideIntermédiaire

RGPD et chatbots IA : Guide de conformité complet

14 mars 2026
18 min de lecture
Équipe Ailog

Comment rendre votre chatbot IA conforme au RGPD. Consentement, droits des utilisateurs, conservation des données et bonnes pratiques.

RGPD et chatbots IA : Guide de conformité complet

Le déploiement d'un chatbot IA pose des défis uniques en matière de protection des données personnelles. Ce guide vous accompagne dans la mise en conformité RGPD de votre assistant conversationnel, de la collecte du consentement à la gestion des droits des utilisateurs.

Prérequis : Avant de plonger dans ce guide, assurez-vous de maîtriser les fondamentaux du RAG et d'avoir lu notre guide parent sur la sécurité et conformité RAG.

Pourquoi le RGPD s'applique aux chatbots IA

Les données personnelles dans un contexte conversationnel

Un chatbot IA collecte et traite de nombreuses données personnelles, souvent sans que l'utilisateur en soit pleinement conscient :

Type de donnéeExemplesNiveau de risque
Identifiants directsNom, email, téléphoneÉlevé
Données de conversationQuestions posées, contexteMoyen à élevé
Métadonnées techniquesIP, user agent, timestampsMoyen
Données inféréesIntentions, préférencesVariable
Données sensiblesSanté, opinions politiquesTrès élevé

Le cas particulier des systèmes RAG

Les systèmes RAG (Retrieval-Augmented Generation) ajoutent une couche de complexité. Non seulement ils collectent les données de conversation, mais ils peuvent également :

  • Stocker les embeddings des requêtes utilisateur
  • Conserver l'historique des sessions pour améliorer la pertinence
  • Indexer des documents contenant des données personnelles
  • Générer des réponses basées sur des données personnelles tierces

Les 7 principes RGPD appliqués aux chatbots

1. Licéité, loyauté et transparence

Votre chatbot doit informer clairement les utilisateurs de la collecte de leurs données.

DEVELOPERpython
from dataclasses import dataclass from typing import Optional from datetime import datetime @dataclass class ConsentRecord: """Enregistrement du consentement utilisateur.""" user_id: str consent_given: bool consent_timestamp: datetime consent_version: str ip_address: str purpose: str class ConsentManager: """Gestionnaire de consentement RGPD pour chatbot.""" CONSENT_TEXT = """ En utilisant ce chatbot, vous acceptez que nous collections et traitions vos messages pour vous fournir des réponses pertinentes. Vos données sont conservées pendant 12 mois et ne sont jamais partagées avec des tiers. Vous pouvez retirer votre consentement à tout moment en tapant /supprimer-mes-donnees. """ def __init__(self, db_connection): self.db = db_connection self.current_version = "2.1" async def check_consent(self, user_id: str) -> bool: """Vérifie si l'utilisateur a donné son consentement.""" record = await self.db.get_consent(user_id) if not record: return False # Vérifier que le consentement est toujours valide return ( record.consent_given and record.consent_version == self.current_version ) async def request_consent(self, user_id: str, ip_address: str) -> str: """Demande le consentement à l'utilisateur.""" return { "type": "consent_request", "message": self.CONSENT_TEXT, "buttons": [ {"text": "J'accepte", "action": "consent_accept"}, {"text": "Je refuse", "action": "consent_decline"}, {"text": "En savoir plus", "action": "privacy_policy"} ] } async def record_consent( self, user_id: str, consent_given: bool, ip_address: str, purpose: str = "chatbot_interaction" ) -> ConsentRecord: """Enregistre le consentement de l'utilisateur.""" record = ConsentRecord( user_id=user_id, consent_given=consent_given, consent_timestamp=datetime.utcnow(), consent_version=self.current_version, ip_address=ip_address, purpose=purpose ) await self.db.save_consent(record) return record

2. Limitation des finalités

Définissez clairement pourquoi vous collectez des données et ne les utilisez pas à d'autres fins.

DEVELOPERpython
from enum import Enum from typing import List, Set class DataPurpose(Enum): """Finalités autorisées pour le traitement des données.""" RESPONSE_GENERATION = "generation_reponse" CONVERSATION_CONTEXT = "contexte_conversation" SERVICE_IMPROVEMENT = "amelioration_service" ANALYTICS = "statistiques_agregees" SUPPORT = "support_client" class PurposeLimiter: """Limite l'utilisation des données aux finalités déclarées.""" def __init__(self): # Mapping données -> finalités autorisées self.allowed_purposes = { "message_content": { DataPurpose.RESPONSE_GENERATION, DataPurpose.CONVERSATION_CONTEXT }, "user_preferences": { DataPurpose.RESPONSE_GENERATION, DataPurpose.SERVICE_IMPROVEMENT }, "conversation_history": { DataPurpose.CONVERSATION_CONTEXT, DataPurpose.SUPPORT }, "usage_metrics": { DataPurpose.ANALYTICS, DataPurpose.SERVICE_IMPROVEMENT } } def can_use_data( self, data_type: str, intended_purpose: DataPurpose ) -> bool: """Vérifie si l'utilisation est autorisée.""" allowed = self.allowed_purposes.get(data_type, set()) return intended_purpose in allowed def get_allowed_purposes(self, data_type: str) -> Set[DataPurpose]: """Retourne les finalités autorisées pour un type de donnée.""" return self.allowed_purposes.get(data_type, set()) def validate_processing( self, data_types: List[str], purpose: DataPurpose ) -> dict: """Valide un traitement avant exécution.""" results = {} for data_type in data_types: results[data_type] = self.can_use_data(data_type, purpose) all_valid = all(results.values()) return { "valid": all_valid, "details": results, "purpose": purpose.value, "blocked_data": [k for k, v in results.items() if not v] }

3. Minimisation des données

Ne collectez que les données strictement nécessaires au fonctionnement du chatbot.

DEVELOPERpython
import re from typing import Dict, Any, List import hashlib class DataMinimizer: """Minimise les données collectées par le chatbot.""" # Patterns de données à ne pas stocker SENSITIVE_PATTERNS = { "credit_card": r"\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b", "ssn_fr": r"\b[12]\s?\d{2}\s?\d{2}\s?\d{2}\s?\d{3}\s?\d{3}\s?\d{2}\b", "phone": r"\b(?:\+33|0)\s?[1-9](?:[\s.-]?\d{2}){4}\b", "email": r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", "iban": r"\b[A-Z]{2}\d{2}(?:\s?\d{4}){4,7}\b", } def __init__(self, config: Dict[str, Any] = None): self.config = config or {} self.redaction_placeholder = "[DONNÉE MASQUÉE]" def minimize_message(self, message: str) -> Dict[str, Any]: """Minimise les données sensibles d'un message.""" minimized = message detected_types = [] for data_type, pattern in self.SENSITIVE_PATTERNS.items(): if re.search(pattern, minimized, re.IGNORECASE): detected_types.append(data_type) minimized = re.sub( pattern, self.redaction_placeholder, minimized, flags=re.IGNORECASE ) return { "original_length": len(message), "minimized_message": minimized, "detected_sensitive_data": detected_types, "was_modified": len(detected_types) > 0 } def minimize_conversation( self, messages: List[Dict[str, Any]] ) -> List[Dict[str, Any]]: """Minimise une conversation entière.""" minimized_messages = [] for msg in messages: result = self.minimize_message(msg.get("content", "")) minimized_messages.append({ **msg, "content": result["minimized_message"], "_minimization_applied": result["was_modified"] }) return minimized_messages def pseudonymize_user_id(self, user_id: str, salt: str) -> str: """Pseudonymise un identifiant utilisateur.""" combined = f"{user_id}:{salt}" return hashlib.sha256(combined.encode()).hexdigest()[:16]

4. Exactitude des données

Les données doivent être exactes et mises à jour. Pour un chatbot, cela concerne principalement la base de connaissances RAG.

DEVELOPERpython
from datetime import datetime, timedelta from typing import Optional import logging class DataAccuracyChecker: """Vérifie et maintient l'exactitude des données RAG.""" def __init__(self, vector_store, document_store): self.vector_store = vector_store self.document_store = document_store self.logger = logging.getLogger(__name__) async def check_document_freshness( self, doc_id: str, max_age_days: int = 90 ) -> Dict[str, Any]: """Vérifie la fraîcheur d'un document indexé.""" doc = await self.document_store.get(doc_id) if not doc: return {"status": "not_found", "doc_id": doc_id} age = datetime.utcnow() - doc.indexed_at is_stale = age > timedelta(days=max_age_days) return { "doc_id": doc_id, "indexed_at": doc.indexed_at.isoformat(), "age_days": age.days, "is_stale": is_stale, "recommendation": "reindex" if is_stale else "ok" } async def flag_outdated_content( self, namespace: str, max_age_days: int = 90 ) -> List[str]: """Identifie les contenus obsolètes à mettre à jour.""" all_docs = await self.document_store.list_by_namespace(namespace) outdated = [] for doc in all_docs: check = await self.check_document_freshness(doc.id, max_age_days) if check.get("is_stale"): outdated.append(doc.id) self.logger.warning( f"Document obsolète détecté: {doc.id} " f"(âge: {check['age_days']} jours)" ) return outdated async def handle_correction_request( self, user_id: str, correction: Dict[str, Any] ) -> Dict[str, Any]: """Traite une demande de correction de données.""" # Log la demande pour audit self.logger.info( f"Demande de correction reçue de {user_id}: {correction}" ) # Créer un ticket de révision ticket = { "type": "data_correction", "user_id": user_id, "requested_at": datetime.utcnow().isoformat(), "correction_details": correction, "status": "pending_review" } return ticket

5. Limitation de la conservation

Définissez des durées de conservation claires et supprimez automatiquement les données expirées.

DEVELOPERpython
from datetime import datetime, timedelta from typing import Dict, List import asyncio class RetentionManager: """Gère la conservation et la suppression des données.""" # Durées de conservation par type de donnée (en jours) RETENTION_POLICIES = { "conversation_messages": 365, # 1 an "user_preferences": 730, # 2 ans "consent_records": 1825, # 5 ans (obligation légale) "analytics_raw": 90, # 3 mois "analytics_aggregated": 1095, # 3 ans "support_tickets": 1095, # 3 ans "embeddings_cache": 30, # 1 mois "session_data": 1, # 1 jour } def __init__(self, db_connection, logger=None): self.db = db_connection self.logger = logger or logging.getLogger(__name__) async def get_retention_period(self, data_type: str) -> int: """Retourne la durée de conservation en jours.""" return self.RETENTION_POLICIES.get(data_type, 365) async def is_expired( self, data_type: str, created_at: datetime ) -> bool: """Vérifie si une donnée a dépassé sa durée de conservation.""" retention_days = await self.get_retention_period(data_type) expiry_date = created_at + timedelta(days=retention_days) return datetime.utcnow() > expiry_date async def cleanup_expired_data(self) -> Dict[str, int]: """Supprime toutes les données expirées.""" results = {} for data_type, retention_days in self.RETENTION_POLICIES.items(): cutoff_date = datetime.utcnow() - timedelta(days=retention_days) deleted_count = await self.db.delete_before( table=data_type, date_column="created_at", cutoff=cutoff_date ) results[data_type] = deleted_count if deleted_count > 0: self.logger.info( f"Supprimé {deleted_count} enregistrements de {data_type} " f"(antérieurs à {cutoff_date.date()})" ) return results async def schedule_deletion( self, user_id: str, data_type: str, delay_days: int = 30 ) -> Dict[str, Any]: """Programme une suppression différée (droit à l'oubli).""" deletion_date = datetime.utcnow() + timedelta(days=delay_days) job = { "user_id": user_id, "data_type": data_type, "scheduled_for": deletion_date.isoformat(), "status": "scheduled" } await self.db.create_deletion_job(job) return { "message": f"Suppression programmée pour le {deletion_date.date()}", "job_id": job.get("id"), "can_cancel_until": deletion_date.isoformat() }

6. Intégrité et confidentialité

Protégez les données contre les accès non autorisés et les altérations.

DEVELOPERpython
from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC import base64 import os class ConversationEncryption: """Chiffrement des conversations stockées.""" def __init__(self, master_key: str): # Dériver une clé à partir du master key kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=b'ailog_salt_v1', # En prod: salt unique par installation iterations=100000, ) key = base64.urlsafe_b64encode(kdf.derive(master_key.encode())) self.cipher = Fernet(key) def encrypt_message(self, message: str) -> str: """Chiffre un message avant stockage.""" return self.cipher.encrypt(message.encode()).decode() def decrypt_message(self, encrypted: str) -> str: """Déchiffre un message pour lecture.""" return self.cipher.decrypt(encrypted.encode()).decode() def encrypt_conversation( self, messages: List[Dict[str, Any]] ) -> List[Dict[str, Any]]: """Chiffre une conversation entière.""" encrypted_messages = [] for msg in messages: encrypted_msg = msg.copy() if "content" in msg: encrypted_msg["content"] = self.encrypt_message(msg["content"]) encrypted_msg["_encrypted"] = True encrypted_messages.append(encrypted_msg) return encrypted_messages class AccessControl: """Contrôle d'accès aux données conversationnelles.""" def __init__(self, db_connection): self.db = db_connection async def can_access_conversation( self, requester_id: str, conversation_id: str, access_type: str = "read" ) -> bool: """Vérifie si un utilisateur peut accéder à une conversation.""" conversation = await self.db.get_conversation(conversation_id) if not conversation: return False # Le propriétaire a tous les droits if conversation.user_id == requester_id: return True # Vérifier les permissions explicites permissions = await self.db.get_permissions( resource_type="conversation", resource_id=conversation_id, user_id=requester_id ) return access_type in permissions.get("allowed_actions", []) async def log_access( self, user_id: str, resource: str, action: str, success: bool ): """Enregistre un accès pour audit.""" await self.db.insert_audit_log({ "timestamp": datetime.utcnow().isoformat(), "user_id": user_id, "resource": resource, "action": action, "success": success, "ip_address": self._get_current_ip() })

7. Responsabilité (Accountability)

Documentez vos traitements et soyez en mesure de démontrer votre conformité.

DEVELOPERpython
from typing import Dict, Any, List from datetime import datetime import json class GDPRDocumentation: """Génère la documentation RGPD requise.""" def generate_processing_record(self) -> Dict[str, Any]: """Génère le registre des traitements (Article 30).""" return { "controller": { "name": "Votre Entreprise SAS", "address": "123 rue Example, 75001 Paris", "contact": "[email protected]" }, "processing_activities": [ { "name": "Chatbot IA - Support client", "purpose": "Répondre aux questions des utilisateurs", "legal_basis": "Consentement (Art. 6.1.a)", "data_categories": [ "Messages de conversation", "Identifiants de session", "Préférences utilisateur" ], "data_subjects": "Visiteurs du site web", "recipients": [ "Équipe support interne", "Sous-traitant hébergement (OVH)" ], "retention": "12 mois", "security_measures": [ "Chiffrement au repos (AES-256)", "Chiffrement en transit (TLS 1.3)", "Pseudonymisation des identifiants", "Contrôle d'accès par rôles" ], "transfers": { "outside_eu": False } } ], "generated_at": datetime.utcnow().isoformat(), "version": "1.0" } def generate_dpia(self) -> Dict[str, Any]: """Génère une analyse d'impact (DPIA) simplifiée.""" return { "project": "Chatbot IA RAG", "assessment_date": datetime.utcnow().date().isoformat(), "necessity_assessment": { "purpose_legitimate": True, "data_minimization": True, "proportionality": True }, "risks_identified": [ { "risk": "Divulgation de données sensibles dans les réponses", "likelihood": "Medium", "impact": "High", "mitigation": "Filtrage des données sensibles en sortie", "residual_risk": "Low" }, { "risk": "Conservation excessive des conversations", "likelihood": "Low", "impact": "Medium", "mitigation": "Politique de rétention automatique", "residual_risk": "Low" } ], "conclusion": "Le traitement peut être mis en œuvre avec les mesures identifiées" }

Implémentation des droits des personnes concernées

Droit d'accès (Article 15)

DEVELOPERpython
class SubjectRights: """Implémentation des droits des personnes concernées.""" def __init__(self, db, encryption, export_service): self.db = db self.encryption = encryption self.export_service = export_service async def handle_access_request( self, user_id: str, verification_token: str ) -> Dict[str, Any]: """Traite une demande d'accès aux données personnelles.""" # Vérifier l'identité du demandeur if not await self._verify_identity(user_id, verification_token): return {"error": "Verification failed", "status": 401} # Collecter toutes les données de l'utilisateur user_data = { "conversations": await self._get_user_conversations(user_id), "preferences": await self.db.get_user_preferences(user_id), "consent_records": await self.db.get_consent_history(user_id), "access_logs": await self.db.get_user_access_logs(user_id) } # Générer un export téléchargeable export_file = await self.export_service.create_export( user_data, format="json", encrypted=True ) return { "status": "success", "data_summary": { "conversations_count": len(user_data["conversations"]), "date_range": self._get_date_range(user_data), "data_types": list(user_data.keys()) }, "download_link": export_file.url, "expires_at": export_file.expires_at } async def _get_user_conversations( self, user_id: str ) -> List[Dict[str, Any]]: """Récupère et déchiffre les conversations utilisateur.""" encrypted_convs = await self.db.get_conversations(user_id) decrypted = [] for conv in encrypted_convs: messages = [] for msg in conv.get("messages", []): if msg.get("_encrypted"): content = self.encryption.decrypt_message(msg["content"]) else: content = msg["content"] messages.append({ "role": msg["role"], "content": content, "timestamp": msg["timestamp"] }) decrypted.append({ "conversation_id": conv["id"], "created_at": conv["created_at"], "messages": messages }) return decrypted

Droit à l'effacement (Article 17)

DEVELOPERpython
async def handle_erasure_request( self, user_id: str, verification_token: str, reason: str = None ) -> Dict[str, Any]: """Traite une demande de suppression (droit à l'oubli).""" if not await self._verify_identity(user_id, verification_token): return {"error": "Verification failed", "status": 401} # Liste des données à supprimer deletion_targets = [ ("conversations", self.db.delete_user_conversations), ("embeddings", self.db.delete_user_embeddings), ("preferences", self.db.delete_user_preferences), ("session_data", self.db.delete_user_sessions), ] # Données à conserver (obligations légales) retained_data = [ "consent_records", # Conservation 5 ans "audit_logs" # Conservation légale ] deletion_results = {} for target_name, delete_func in deletion_targets: try: count = await delete_func(user_id) deletion_results[target_name] = { "status": "deleted", "count": count } except Exception as e: deletion_results[target_name] = { "status": "error", "error": str(e) } # Journaliser la demande d'effacement await self.db.log_erasure_request({ "user_id": user_id, "requested_at": datetime.utcnow().isoformat(), "reason": reason, "results": deletion_results, "retained": retained_data }) return { "status": "completed", "deleted": deletion_results, "retained": { "data_types": retained_data, "reason": "Conservation légale obligatoire" }, "confirmation_sent_to": await self._get_user_email(user_id) }

Droit à la portabilité (Article 20)

DEVELOPERpython
async def handle_portability_request( self, user_id: str, verification_token: str, format: str = "json" ) -> Dict[str, Any]: """Exporte les données dans un format portable.""" if not await self._verify_identity(user_id, verification_token): return {"error": "Verification failed", "status": 401} # Données portables (fournies par l'utilisateur) portable_data = { "conversations": await self._get_user_conversations(user_id), "preferences": await self.db.get_user_preferences(user_id), "documents_uploaded": await self.db.get_user_documents(user_id) } # Métadonnées d'export export_metadata = { "exported_at": datetime.utcnow().isoformat(), "format": format, "schema_version": "1.0", "source": "Ailog Chatbot", "user_id_hash": self._hash_user_id(user_id) } if format == "json": export_content = json.dumps({ "metadata": export_metadata, "data": portable_data }, indent=2, ensure_ascii=False) elif format == "csv": export_content = self._convert_to_csv(portable_data) else: return {"error": f"Format non supporté: {format}"} # Créer le fichier d'export export_file = await self.export_service.create_download( content=export_content, filename=f"export_{user_id[:8]}_{format}", expires_hours=72 ) return { "status": "ready", "download_url": export_file.url, "format": format, "size_bytes": len(export_content), "expires_at": export_file.expires_at, "checksum": self._compute_checksum(export_content) }

Interface utilisateur pour la conformité

Bannière de consentement pour chatbot

DEVELOPERtypescript
// components/ChatConsentBanner.tsx import { useState } from 'react'; interface ConsentBannerProps { onAccept: () => void; onDecline: () => void; onMoreInfo: () => void; } export function ChatConsentBanner({ onAccept, onDecline, onMoreInfo }: ConsentBannerProps) { const [expanded, setExpanded] = useState(false); return ( <div className="bg-gray-50 border border-gray-200 rounded-lg p-4 mb-4"> <p className="text-sm text-gray-700 mb-3"> Ce chatbot utilise l'IA pour répondre à vos questions. Vos messages sont traités pour générer des réponses pertinentes. </p> {expanded && ( <div className="text-xs text-gray-600 mb-3 space-y-2"> <p> <strong>Données collectées :</strong> Messages, horodatage, identifiant de session anonyme. </p> <p> <strong>Durée de conservation :</strong> 12 mois maximum. </p> <p> <strong>Vos droits :</strong> Accès, rectification, effacement. Tapez /mes-donnees dans le chat pour les exercer. </p> </div> )} <div className="flex items-center gap-2"> <button onClick={onAccept} className="px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700" > Accepter </button> <button onClick={onDecline} className="px-4 py-2 border border-gray-300 text-sm rounded hover:bg-gray-100" > Refuser </button> <button onClick={() => setExpanded(!expanded)} className="px-4 py-2 text-sm text-gray-600 hover:text-gray-900" > {expanded ? 'Moins de détails' : 'Plus de détails'} </button> </div> </div> ); }

Commandes intégrées au chatbot

DEVELOPERpython
class GDPRChatCommands: """Commandes RGPD accessibles directement dans le chat.""" COMMANDS = { "/mes-donnees": "access_request", "/supprimer-mes-donnees": "erasure_request", "/exporter-mes-donnees": "portability_request", "/retirer-consentement": "withdraw_consent", "/politique-confidentialite": "privacy_policy", "/aide-rgpd": "gdpr_help" } async def handle_command( self, command: str, user_id: str ) -> Dict[str, Any]: """Traite une commande RGPD.""" action = self.COMMANDS.get(command.lower()) if not action: return None # Pas une commande RGPD if action == "access_request": return { "type": "gdpr_response", "message": """ 📋 **Demande d'accès à vos données** Pour recevoir une copie de vos données, nous devons vérifier votre identité. Un email de vérification va vous être envoyé. Une fois vérifié, vous recevrez un lien de téléchargement valide 72h contenant : - Vos conversations - Vos préférences - Votre historique de consentement """, "action_required": "email_verification" } elif action == "erasure_request": return { "type": "gdpr_response", "message": """ 🗑️ **Demande de suppression de vos données** Vous pouvez demander la suppression de vos données personnelles. Seront supprimés : - Toutes vos conversations - Vos préférences - Vos données de session Seront conservés (obligation légale) : - Registre de consentement (5 ans) - Logs de sécurité (1 an) ⚠️ Cette action est irréversible. Confirmez-vous la suppression ? """, "confirmation_required": True, "action": "confirm_erasure" } elif action == "gdpr_help": return { "type": "gdpr_response", "message": """ 🔒 **Vos droits sur vos données** Commandes disponibles : `/mes-donnees` - Voir quelles données nous avons sur vous `/exporter-mes-donnees` - Télécharger vos données `/supprimer-mes-donnees` - Demander l'effacement `/retirer-consentement` - Retirer votre consentement `/politique-confidentialite` - Lire notre politique Questions ? Contactez notre DPO : [email protected] """ } # ... autres actions

Checklist de conformité RGPD

Avant de déployer votre chatbot, vérifiez ces points :

Bases légales et consentement

  • Consentement explicite demandé avant la première interaction
  • Possibilité de refuser sans perte de fonctionnalité critique
  • Mécanisme de retrait du consentement facilement accessible
  • Registre des consentements horodaté et conservé

Transparence

  • Information claire sur les données collectées
  • Mention de l'utilisation de l'IA
  • Lien vers la politique de confidentialité
  • Contact du DPO visible

Droits des personnes

  • Procédure d'accès aux données (< 30 jours)
  • Procédure de rectification
  • Procédure d'effacement (droit à l'oubli)
  • Export des données en format portable

Sécurité

  • Chiffrement des données au repos
  • Chiffrement en transit (TLS)
  • Contrôle d'accès par rôles
  • Journalisation des accès

Conservation

  • Durées de conservation définies par type de donnée
  • Suppression automatique des données expirées
  • Procédure de purge testée

Documentation

  • Registre des traitements à jour
  • DPIA réalisée si nécessaire
  • Procédures de violation de données documentées
  • Contrats de sous-traitance (DPA) signés

Conclusion

La conformité RGPD d'un chatbot IA n'est pas une option mais une obligation légale. En implémentant les mesures décrites dans ce guide, vous protégez non seulement vos utilisateurs mais aussi votre entreprise contre les risques juridiques et réputationnels.

Points clés à retenir :

  1. Le consentement est la base - Pas de traitement sans consentement explicite
  2. Minimisez les données - Ne collectez que le strict nécessaire
  3. Sécurisez tout - Chiffrement, contrôle d'accès, journalisation
  4. Documentez - Registre des traitements, DPIA, procédures
  5. Facilitez l'exercice des droits - Interfaces claires, délais respectés

Pour aller plus loin

FAQ

Oui, si le chatbot collecte des données personnelles (messages, email, historique), le consentement est requis selon le RGPD. Vous devez informer l'utilisateur avant la première interaction et lui donner la possibilité de refuser. L'intérêt légitime peut s'appliquer dans certains cas (support client existant), mais le consentement reste la base juridique la plus sûre.
Le RGPD impose de ne conserver les données que le temps nécessaire à la finalité. Pour un chatbot support, 12 mois est une durée raisonnable et justifiable. Les données agrégées anonymisées peuvent être conservées plus longtemps pour les statistiques. Documentez votre politique de rétention et appliquez-la automatiquement.
Vous disposez de 30 jours pour répondre. Le processus doit être automatisé : vérification d'identité, extraction de toutes les données de l'utilisateur (conversations, préférences, logs), génération d'un export lisible (JSON ou PDF), et envoi sécurisé. Prévoyez une commande directement dans le chat (/mes-donnees) pour faciliter les demandes.
C'est un point critique. Si vous utilisez un LLM externe (OpenAI, Anthropic), vous êtes responsable du traitement. Vérifiez le DPA du fournisseur, assurez-vous que les données ne sont pas utilisées pour l'entraînement, et si possible, minimisez les données avant envoi. Les LLMs hébergés en Europe (Mistral, modèles self-hosted) simplifient la conformité.
Une DPIA est recommandée si le chatbot traite des données sensibles (santé, opinions) ou opère à grande échelle. Elle n'est pas obligatoire pour un chatbot support standard, mais elle démontre votre diligence en cas de contrôle. Documentez les risques identifiés et les mesures de mitigation. --- **Besoin d'un chatbot IA conforme RGPD clé en main ?** [Ailog](https://ailog.fr) propose des solutions RAG hébergées en France avec conformité RGPD native. Déployez votre assistant en 3 minutes sans vous soucier de la conformité.

Tags

RAGRGPDconformitéchatbotprotection données

Articles connexes

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !