FlowKit

Publier automatiquement sur Bluesky avec n8n et l'IA

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

Bluesky a dépassé les 35 millions de comptes début 2026, porté par une base technique et journalistique disproportionnée par rapport à sa taille. Martin Kleppmann et ses co-auteurs (dont Jay Graber, la CEO de Bluesky), dans Bluesky and the AT Protocol: Usable Decentralized Social Media (ACM CoNEXT 2024), décrivent une architecture pensée dès l'origine pour que n'importe quel client tiers puisse lire et écrire sur le réseau sans passer par une app officielle — exactement ce qui rend Bluesky, contrairement à Threads ou X, aussi simple à automatiser depuis n8n. Ce guide couvre les deux façons de le faire : via le node communautaire existant, et via l'AT Protocol en direct pour qui veut tout maîtriser.

Ce qu'expose l'AT Protocol

Bluesky n'a pas d'API REST « classique » : le réseau tourne sur l'AT Protocol, où chaque compte possède un dépôt de données (repository) hébergé sur un serveur (PDS, Personal Data Server) — bsky.social par défaut si vous n'auto-hébergez pas le vôtre. Trois appels XRPC suffisent pour publier :

  • com.atproto.server.createSession : authentification avec un identifier (handle ou email) et un app password, jamais le mot de passe principal du compte. Renvoie un accessJwt (valide quelques minutes) et un refreshJwt (valide environ 90 jours).
  • com.atproto.repo.uploadBlob : envoi d'un fichier binaire (image, jusqu'à 1 Mo pour l'instant côté serveur officiel) directement dans le corps de la requête — pas besoin d'URL publique, contrairement à Instagram, Threads ou X, qui exigent tous une image déjà hébergée quelque part.
  • com.atproto.repo.createRecord : création du post proprement dit, avec collection: "app.bsky.feed.post" et le contenu du texte, des éventuels embed (image, lien externe) et facets.

Côté limites : un post fait au maximum 300 graphèmes et 3000 octets de texte, jusqu'à 4 images par post, et l'API applique une limite glissante d'environ 5000 points par heure (une création de contenu coûte 3 points, soit environ 1666 posts/heure) et 35000 points par jour — un plafond que la plupart des comptes édito n'approchent jamais.

Node communautaire ou HTTP Request : les deux options dans n8n

Le node communautaire @muench-dev/n8n-nodes-bluesky (et son fork enrichi n8n-nodes-bluesky-enhanced) couvre déjà l'essentiel : création de post avec image et texte alternatif, réponses, citations, cartes de lien avec titre et description. Installation en deux minutes depuis Settings > Community Nodes — voir notre guide complet des community nodes n8n pour la marche à suivre et les précautions de sécurité avant d'installer un package tiers en production, surtout un qui manipule des credentials.

L'appel direct en HTTP Request garde tout son intérêt si votre pipeline a besoin d'un contrôle fin sur les facets (liens et mentions calculés dynamiquement par l'IA) ou si vous préférez ne dépendre d'aucun mainteneur tiers pour rester à jour avec l'API. C'est l'approche détaillée ci-dessous ; elle se transpose sans effort au node communautaire pour les cas plus simples.

Le pipeline en n8n

1. Déclencheur planifié et sujet du jour

Un Schedule Trigger lit une ligne « à publier » dans le même calendrier éditorial que pour les autres réseaux — voir notre article sur le calendrier éditorial Notion pour les réseaux sociaux.

2. Génération du texte par un AI Agent

Un node AI Agent rédige le post à partir du sujet, avec un prompt système qui cadre le ton (Bluesky penche technique et conversationnel, moins promotionnel qu'Instagram) et la contrainte dure des 300 graphèmes. Un Structured Output Parser verrouille la sortie sur des champs texte, liens (URL + texte visible) et alt_text pour l'image éventuelle, évitant à l'agent de glisser du Markdown que Bluesky n'interprète pas.

3. Image optionnelle, uploadée en binaire

Pour un post avec visuel, le node OpenAI (ressource Image) génère l'illustration — voir le guide de génération d'images par IA dans n8n. Contrairement au pipeline Instagram ou Threads, pas besoin de bucket public : le fichier binaire part directement vers uploadBlob, ce qui simplifie ce point du workflow d'un cran.

4. Relecture humaine avant publication

Le brouillon (texte, liens détectés, image) part sur Slack pour validation, avec le pattern human-in-the-loop décrit dans notre article sur l'approbation humaine avec le node Wait et des boutons Slack : un node Wait en mode On Webhook Call bloque le workflow jusqu'au clic « Publier » ou « Rejeter ».

5. Authentification, upload, puis création du post

1) POST https://bsky.social/xrpc/com.atproto.server.createSession
   Body : { "identifier": "moncompte.bsky.social", "password": "<app_password>" }
   → renvoie { "accessJwt": "...", "did": "did:plc:..." }

2) POST https://bsky.social/xrpc/com.atproto.repo.uploadBlob   (si image)
   Headers : Authorization: Bearer <accessJwt>, Content-Type: image/jpeg
   Body : le fichier binaire brut
   → renvoie { "blob": { "$type": "blob", "ref": {...}, "mimeType": "image/jpeg", "size": ... } }

3) POST https://bsky.social/xrpc/com.atproto.repo.createRecord
   Body : {
     "repo": "<did>",
     "collection": "app.bsky.feed.post",
     "record": {
       "$type": "app.bsky.feed.post",
       "text": "{{ $json.texte }}",
       "createdAt": "{{ $now.toISO() }}",
       "langs": ["fr"],
       "facets": [ { "index": { "byteStart": 42, "byteEnd": 61 },
                     "features": [{ "$type": "app.bsky.richtext.facet#link", "uri": "https://..." }] } ],
       "embed": { "$type": "app.bsky.embed.images#main",
                  "images": [{ "image": "<blob>", "alt": "{{ $json.alt_text }}" }] }
     }
   }

Comme pour tout appel API asynchrone soumis à quota, appliquez les bonnes pratiques de retry et timeout sur l'appel createRecord, en particulier pour absorber un éventuel 429 sans dupliquer le post au retry suivant.

Le piège des facets : des octets, pas des caractères

Bluesky n'interprète aucun Markdown dans text : un lien cliquable ou une mention doit être déclaré à part, dans le tableau facets, avec une position byteStart/byteEnd mesurée en octets UTF-8 du texte, bornes incluse/exclusive. C'est là que la plupart des pipelines automatisés en français trébuchent en premier : un caractère accentué (é, è, à, ç, œ…) occupe deux octets en UTF-8, pas un seul. Calculer les positions en comptant les caractères de la chaîne plutôt que sa représentation en octets décale silencieusement chaque facet situé après le premier accent — le lien pointe alors sur le mauvais fragment de texte, ou sur rien du tout. Dans un node Code, encodez le texte en UTF-8 avant de chercher les positions (Buffer.from(texte, "utf8") en JavaScript) plutôt que d'indexer directement la chaîne source.

Authentification : pas de renouvellement de token à orchestrer

Contrairement à Threads ou X, qui imposent un échange puis un rafraîchissement périodique d'un token longue durée, l'app password Bluesky ne change jamais : recréez simplement une session (createSession) au début de chaque exécution du workflow plutôt que de persister un accessJwt de courte durée. Le coût est négligeable — 30 créations de session autorisées par 5 minutes — et cela évite tout le mécanisme de rafraîchissement à surveiller.

Pièges fréquents

  • Utiliser le mot de passe principal du compte au lieu d'un app password dédié, généré et révocable indépendamment depuis les réglages Bluesky.
  • Compter les positions des facets en caractères plutôt qu'en octets, l'erreur la plus fréquente sur du contenu en français.
  • Dépasser 3000 octets de texte en ne comptant que les 300 graphèmes visibles : un post riche en emojis ou en caractères accentués peut atteindre la limite d'octets avant celle de caractères.
  • Oublier le champ createdAt, requis dans chaque enregistrement app.bsky.feed.post, au format ISO 8601.

Pour aller plus loin

Le pipeline décrit ici — calendrier éditorial, génération IA cadrée par un output structuré, relecture Slack avant publication — reprend les mêmes briques que nos guides sur Threads et X (Twitter) : si l'un de ces pipelines tourne déjà chez vous, l'essentiel se réutilise tel quel pour Bluesky, seule la couche d'appels API change de forme. Pour partir d'une base de tri et de rédaction assistée par IA déjà prête à l'emploi, le Pack Inbox IA (79 €) fournit les mêmes patterns de génération et de validation humaine, appliqués cette fois à une boîte mail plutôt qu'à un fil social.

FAQ

Questions fréquentes

Existe-t-il un node natif n8n pour Bluesky ?

Pas de node officiel maintenu par l'équipe n8n, mais contrairement à Threads ou X, Bluesky bénéficie d'un node communautaire mature, @muench-dev/n8n-nodes-bluesky (et sa variante enrichie n8n-nodes-bluesky-enhanced), qui couvre la création de posts, l'upload d'images avec texte alternatif, les réponses et les citations. Pour un contrôle total sur les facets et la limite de débit, l'appel direct à l'AT Protocol via HTTP Request reste l'alternative la plus fiable.

Faut-il utiliser mon mot de passe principal Bluesky dans n8n ?

Non, et il ne faut surtout pas le faire. Bluesky impose un « app password » généré depuis Réglages > Confidentialité et sécurité, révocable indépendamment du mot de passe principal et sans accès aux réglages du compte. C'est ce mot de passe applicatif qui doit être stocké dans la credential n8n, jamais l'identifiant principal.

Quelle est la limite de caractères et de fréquence de publication sur Bluesky ?

Un post est limité à 300 graphèmes et 3000 octets de texte. Côté fréquence, l'API applique une limite par points glissante d'environ 5000 points par heure et 35000 par jour et par compte, ce qui autorise dans la pratique environ 1666 créations de contenu par heure sur une fenêtre glissante — largement suffisant pour une cadence éditoriale normale.

Comment gérer les liens et les mentions dans un post généré par l'IA ?

Bluesky n'interprète pas le Markdown : chaque lien ou mention doit être déclaré séparément dans un tableau `facets`, avec une position de départ et de fin exprimée en octets UTF-8 du texte, et non en nombre de caractères. C'est un piège fréquent en français, où les caractères accentués (é, è, à, ç) occupent deux octets chacun, ce qui décale silencieusement la position calculée si elle est comptée en caractères plutôt qu'en octets.

Bundle FlowKit Complet

269 €