Quand on parle d'automatiser les réseaux sociaux, on s'arrête souvent à « publier tous les matins à 9 h » ou « laisser l'IA rédiger le texte ».
Mais le vrai défi n'est pas le bouton de publication.
Ne diffuser que les bons articles. Ne jamais publier deux fois. Ne pas tout arrêter parce qu'un service est en panne. Ne pas forcer un CAPTCHA. Ne confier à un humain que ce que seul un humain peut faire. Et, une fois diffusé, se servir des résultats pour changer la manière de diffuser la fois suivante.
C'est quand tout cela est relié qu'on peut enfin dire que la diffusion est automatisée.
Dès qu'on gère 12 langues, plusieurs réseaux sociaux et même une newsletter, la diffusion n'est plus une simple fonction de programmation de posts. C'est un petit système distribué.
1. Le but n'est pas « zéro humain » : c'est « les humains ne traitent que les exceptions »
Si l'on fixe pour objectif d'automatisation « personne ne touche à rien », la conception dérape.
Les services externes réels ont des CAPTCHA pour vérifier que vous êtes humain, des vérifications par SMS, de la double authentification (2FA), des contrôles d'identité, l'acceptation explicite des conditions d'utilisation, la validation des applis de développeur, etc. Ce n'est pas une panne. C'est une frontière que le service a posée exprès : « ici, seul le titulaire passe ».
La forme finale ressemble donc à ceci :
Génération de l'article → Contrôle de qualité → Version de chaque langue → Mise en production → Relecture du HTML de production → Candidat à la diffusion → Texte de publication de chaque langue → Réseaux sociaux et newsletter → Collecte des résultats → Décision pour la prochaine diffusion
Si, en chemin, un point ne peut être traité que par un humain, on ne lui confie que ce cas-là.
Par exemple, si seul X en japonais tombe sur un CAPTCHA, seul X en japonais attend. Inutile de mettre Bluesky en anglais, Facebook en français, la newsletter, l'analyse d'audience et la génération du prochain article au coin.
Pas besoin que les 12 langues prennent le deuil à cause d'un seul CAPTCHA.
Les produits de workflow durable (durable workflow) comme Cloudflare Workflows sont eux aussi conçus pour conserver un état longtemps, relancer les étapes en échec et attendre des événements externes ou une validation humaine. L'essentiel n'est pas d'utiliser tel produit, mais de traiter « l'attente d'un humain » comme un état du système, et non comme un arrêt.
2. Séparer « l'article est prêt » de « on peut le diffuser »
Si l'on branche la couche de diffusion directement sur la génération d'articles, les accidents sont faciles.
Le Markdown est enregistré. La traduction est terminée. Le build est passé.
Rien de tout cela ne garantit que « le lecteur peut ouvrir cette URL maintenant et la lire correctement ».
C'est pourquoi l'unité diffusable n'est pas le nom de l'article, mais
articleId × locale × contentSha
Et pour les réseaux sociaux, on affine jusqu'à
articleId × locale × contentSha × platform × campaignType
Le point important ici, c'est contentSha. Même avec la même URL, si le texte a été mis à jour, c'est une autre révision. Un post écrit pour l'ancien texte ne doit pas être lancé comme annonce du nouveau.
Et la condition pour passer quelque chose à la diffusion n'est pas « c'est sur GitHub », mais avoir relu et vérifié le HTML de production de ce locale et de ce contentSha.
Ce qu'il faut à l'entrée de la publication automatique, ce n'est pas « y a-t-il un manuscrit ? », mais « y a-t-il un produit fini que le lecteur peut ouvrir maintenant ? ».
3. Un délai dépassé ne veut pas dire un échec : se tromper ici crée des posts jumeaux
Ce qui fait peur avec les API externes, ce ne sont pas les erreurs claires, mais les erreurs ambiguës.
Vous avez envoyé le post à l'API. De votre côté, le délai est dépassé. Pas de réponse.
À ce moment-là, si vous vous dites :
« On dirait que ça a échoué. Je renvoie »,
et que le premier envoi avait en fait réussi, deux posts identiques apparaissent.
« L'API n'a pas répondu, alors par précaution j'ai publié le même article trois fois » : c'est l'histoire d'épouvante de l'automatisation.
Cloudflare Queues adopte par défaut la livraison at-least-once (au moins une fois), et il arrive rarement qu'un même message soit livré plusieurs fois. C'est pourquoi la documentation officielle recommande aussi de dédupliquer avec un identifiant unique ou une clé d'idempotence (idempotency key).
On crée donc une clé déterministe pour chaque envoi :
sha256(articleId + locale + contentSha + platform + campaignType)
Dans la table des accusés de réception, cette clé est déclarée UNIQUE.
En cas de délai dépassé, au lieu de renvoyer aussitôt, on suit cet ordre :
- Vérifier l'enregistrement des accusés de réception
- Si l'on peut relire côté fournisseur, vérifier si c'est déjà publié
- Ne réessayer que si l'on a confirmé que ce n'est pas publié
La file (Queue) n'est pas une « magie qui exécute exactement une fois ». La conception consiste à faire converger le résultat vers une seule exécution même en cas de doublons.
4. Enfermer les pannes dans le « plus petit périmètre », pas dans « tout le système »
Le plus dommage, en automatisation, c'est de promouvoir une seule erreur en panne générale.
Au minimum, on découpe le domaine de panne (failure domain) en
platform × locale × account
Si l'authentification de X en japonais a expiré, seul celui-ci passe en BLOCKED.
Si Bluesky en anglais renvoie un 429, seul celui-ci passe en RETRY_WAIT.
Si une page Facebook attend une vérification d'identité, seule celle-ci passe en HUMAN_ACTION_REQUIRED.
Les autres continuent.
Les états ne peuvent pas non plus se limiter à « succès / échec ». Mieux vaut les découper ainsi pour refléter la réalité :
- READY
- ACTIVE
- DEGRADED_BUT_RUNNING
- HUMAN_ACTION_REQUIRED
- BLOCKED_PROVIDER
- RETRY_WAIT
- DISABLED_BY_POLICY
Si, sur 15 lignes au total, 14 fonctionnent et une seule attend un humain, l'état global n'est pas « arrêt total ». Il se rapproche de DEGRADED_BUT_RUNNING.
Face à un 429, la force de volonté ne sert à rien. S'il y a un Retry-After, on le respecte. Pour les 5xx, un backoff exponentiel plafonné. Pour les 401/403, s'il existe une voie légitime de renouvellement des identifiants, on répare une fois ; si cela ne marche toujours pas, on n'arrête que le compte concerné.
Les CAPTCHA et vérifications humaines n'entrent pas dans une boucle de nouvelle tentative automatique. Aucune API ne devient humaine après 100 coups.
5. La Human Handoff Queue doit être un ordre de travail, pas un « au secours »
Si le mécanisme de transmission aux humains est bâclé, il reste un énorme travail manuel au bout de l'automatisation.
Une mauvaise transmission ressemble à ça :
« Les réseaux sociaux sont à l'arrêt. Merci de vérifier. »
Vérifier quoi ? Où ? Juste se connecter ? Faut-il aussi modifier des réglages ? Et que faire ensuite ?
Une bonne transmission contient, au minimum, pour chaque cas :
- platform
- locale
- account
- blockerType
- heure de détection
- heure à laquelle on peut réessayer
- URL à ouvrir
- ce que l'humain doit faire
- ce que l'humain ne doit pas faire
- ce que le système automatique revérifiera ensuite
- le périmètre que ce blocage arrête
- si le reste du travail peut continuer
Par exemple :
« Connectez-vous au compte officiel de cette langue et terminez uniquement le CAPTCHA affiché. Ne modifiez ni les réglages de publication ni le profil. Ensuite, à la prochaine ronde, le système relira l'état d'authentification et reprendra par une publication d'essai (canary). »
Avec ça, on comprend du premier coup.
Et surtout : on n'automatise pas la résolution du CAPTCHA.
Utiliser un solveur, falsifier le défi, contourner par des voies non officielles : ce n'est pas de l'automatisation, c'est aller vers la violation de la frontière fixée par l'autre partie.
On retire les humains de la publication quotidienne et on ne leur laisse que la frontière que la machine ne peut pas franchir légitimement.
Mots de passe, jetons OAuth d'accès et de rafraîchissement, cookies de session, codes SMS/2FA, codes de récupération et secrets d'API privés ne restent ni sur GitHub ni dans les journaux ordinaires. Sur GitHub, on ne garde que les informations non secrètes nécessaires à la reprise : identifiant public, état, erreur assainie (sanitized), identifiant d'accusé de réception, URL publique du post, etc.
6. Ne pas mélanger publication automatique et bot d'engagement
Qu'un compte officiel publie automatiquement les articles de son propre site est une chose ; automatiser les mentions « j'aime », les abonnements, les réponses et jusqu'aux messages privés en est une autre.
Les Automation Rules de X, dans leur version d'avril 2026, autorisent les publications automatiques utiles et informatives qui respectent les règles, mais interdisent de contourner les limites de débit (rate limit) de l'API, l'automatisation hors API qui manipule un site web par script, ainsi que les publications de spam ou en double. Les « j'aime » automatiques sont aussi interdits.
Les valeurs initiales peuvent donc rester très sobres :
- AUTO_PUBLISH = true
- AUTO_LIKE = false
- AUTO_FOLLOW = false
- AUTO_UNFOLLOW = false
- AUTO_REPLY = false
- AUTO_DM = false
On commence par limiter la responsabilité à « livrer correctement les articles officiels ».
Bluesky permet aussi de créer des posts via son API officielle, et chaque post peut porter une information de langue. Autrement dit, en exploitation multilingue, il est plus naturel d'aligner le texte et les métadonnées de langue de chaque locale que d'envoyer partout le texte anglais.
L'automatisation par navigateur se limite à un appui pour des situations comme la configuration initiale des comptes, où il n'y a pas d'API officielle ou où l'action humaine est permise. Pour la diffusion courante, on s'appuie autant que possible sur les API officielles et l'authentification officielle.
Les canaux initiaux se choisissent par locale, par exemple : ja→X, en→X/Bluesky, ko→X, zh-Hans→Weibo, zh-Hant→Facebook/Threads, es・pt-BR・id・th・vi・fr→Facebook, de→Facebook/X. Les surfaces centrées sur l'image et la vidéo, comme Instagram, TikTok et Reels, passent en seconde phase, une fois la génération de cartes et le contrôle qualité des médias (media QA) stabilisés. Les API, politiques d'automatisation et conditions d'utilisation de chaque plateforme doivent toujours être revérifiées au moment de la mise en œuvre.
7. Exploiter 12 langues, ce n'est pas un « concours de traduction de posts japonais »
Sur les sites multilingues, il y a un accident classique.
On a traduit l'article japonais en 12 langues. On a rédigé un seul texte de réseau social en japonais. On l'a aussi traduit en 11 langues. C'est fini.
Dans ce cas, l'intérêt d'avoir mis le corps du texte en 12 langues s'amenuise.
Le texte du post se fait en lisant le corps réellement publié dans ce locale, comme si le compte officiel du site dans cette langue lâchait un petit commentaire.
La forme de base est courte :
Ça, c'est le genre de truc discret qui pose le plus de problèmes. 🫠 URL
ou encore,
Ah, ça aussi, ça peut s'automatiser. 👀 URL
Pas besoin de long résumé ni de « à ne pas manquer », « choquant » ou « à voir tout de suite ». Et fabriquer un faux témoignage, comme si un tiers était tombé dessus par hasard et en avait été ému, est bizarre pour un post du site lui-même.
La personnalité de la marque est commune, mais le texte est naturel dans chaque langue. On ne fait pas semblant que ce soient des personnes différentes qui gèrent les comptes.
De plus, la médecine, le droit, l'investissement, les grosses sommes d'argent, les catastrophes, les crimes, les décès, l'automutilation, la violence, les violences sexuelles, les mineurs, la sécurité, la politique et les élections, ainsi que les conflits violents, passent en serious mode.
Dans ce cas, en principe, pas d'emoji, pas de sensationnalisme et pas d'affirmation allant au-delà de l'article. Pour un article politique, on n'ajoute pas automatiquement de soutien (endorsement).
Le « mode blague à fond » n'est pas un réglage universel. Pour un article sur les ambulances, inutile de mettre 🫠.
8. La newsletter n'est pas la « version e-mail des réseaux sociaux » : c'est la même philosophie de diffusion sur un autre adaptateur
La newsletter non plus ne doit pas partir directement de la génération du texte.
Au minimum, on conserve
- explicit opt-in
- locale
- topics
- consentAt
- status
- unsubscribeAt
- createdAt
et l'on n'envoie pas plusieurs fois le même article.
L'adresse e-mail de contact et le dispositif d'envoi en masse sont aussi séparés logiquement.
Pour les réponses des lecteurs, on peut utiliser le guichet existant, mais la base d'envoi doit être un adaptateur remplaçable plus tard par un fournisseur dédié.
Gmail exige des expéditeurs en masse une authentification d'envoi, d'éviter le spam et les courriels non sollicités, et un mécanisme de désabonnement facile, et fait du désabonnement une exigence importante pour les messages d'abonnement.
Le désabonnement n'est pas « ça s'arrêtera sans doute au prochain lot » : la personne est retirée immédiatement des destinataires.
La valeur d'une newsletter n'est pas de collecter des adresses. C'est de donner au lecteur l'information qu'il a demandée, à la fréquence qu'il a demandée, et de le laisser arrêter dès qu'il le souhaite.
9. Si le KPI, ce sont les « j'aime », on finit par fabriquer une machine à chasser les « j'aime »
Quand on introduit une amélioration automatique, ce qu'on choisit comme fonction objectif est déterminant.
Si l'on maximise seulement les « j'aime » des réseaux sociaux, les titres racoleurs, les affirmations extrêmes et les sujets qui frisent la polémique gagnent facilement.
Mais ce que veut vraiment un site d'articles est autre chose.
On peut par exemple fixer les priorités ainsi :
- site visit
- meaningful reading
- next article
- return visit
- newsletter signup
On donne donc plus de poids à « est-ce que cette personne est venue sur le site grâce à ce post ? », « a-t-elle vraiment lu ? », « est-elle passée à l'article suivant ? » et « est-elle revenue ? ».
Les campagnes de diffusion se divisent aussi en
- NEW
- UPDATED
- TRENDING
- POPULAR
- EVERGREEN
On ne republie pas avec « grosse mise à jour ! » pour avoir corrigé une seule lettre. UPDATED est réservé aux mises à jour significatives (material update).
Pour POPULAR et TRENDING aussi, s'il existe déjà une mesure d'audience réelle, on la réutilise. Pas besoin de créer un classement de popularité à part pour la diffusion et de laisser deux chiffres se faire la guerre.
L'horaire de diffusion ne se décide pas non plus par un préjugé du genre « c'est du japonais, donc 20 h », mais en explorant les locale × country × platform × weekday × hour réels. Au début, on essaie plusieurs créneaux (slots), puis on resserre quand les données se sont accumulées.
10. En pratique : on ne « publie » pas, on fait avancer l'état
L'exploitation réelle se comprend mieux comme une suite de transitions d'état.
- L'article du locale cible est mis en production.
- On relit le HTML de production du contentSha exact et on le marque PRODUCTION_VERIFIED.
- On crée le candidat à la diffusion avec articleId × locale × contentSha × platform × campaignType.
- On lit le texte de ce locale et l'on génère un post court.
- On contrôle l'interdiction du hype, le serious mode, la longueur, l'URL et la langue.
- On le place dans l'outbox avec l'idempotency key.
- On l'envoie par l'API officielle du fournisseur.
- Au-delà de l'accusé de réception de l'API, si possible, on relit le post public.
- On collecte les visites sur le site, la lecture complète, l'article suivant et le retour.
- On s'en sert pour la prochaine décision entre NEW / UPDATED / TRENDING / POPULAR / EVERGREEN.
Si un CAPTCHA apparaît en chemin, seul ce périmètre passe en HUMAN_ACTION_REQUIRED.
Pour un 429, RETRY_WAIT.
Si le fournisseur est en panne, BLOCKED_PROVIDER.
Le reste avance.
On ne tire pas non plus sur 15 comptes d'un coup dès le départ. Pour chaque adaptateur, on passe par
la relecture de l'authentification (auth readback) → un essai à blanc (dry run) → un canary sur un vrai article → l'accusé de réception → la relecture publique (public readback) → la vérification du locale → la vérification de la suppression des doublons → la vérification de l'attribution dans l'analyse d'audience
avant d'élargir.
Et l'entrée que voit l'exploitant est regroupée dans un seul current-status.
Côté implémentation aussi, plutôt que de faire naître une seconde usine à articles et un second scheduler pour la diffusion, il est plus difficile de multiplier les sources de vérité si l'on se raccorde au propriétaire de publication existant comme post-publication child (processus enfant post-publication) après PRODUCTION_VERIFIED, en réutilisant le durable runtime et le state store déjà en place.
Si, pour répondre à « où en est-on ? », un humain doit aller déterrer 15 JSON et journaux, à ce moment-là l'automatisation lui rend le travail.
Le plus important dans la diffusion automatique, ce n'est pas que « rien n'échoue ».
C'est que, même en cas d'échec, on sache où ça s'est arrêté, que le périmètre de l'arrêt soit petit, que seul ce que seuls les humains peuvent faire leur parvienne, que le reste avance tout seul et qu'après rétablissement on reprenne là où l'on s'était arrêté sans rien exécuter en double.
Supprimer le bouton de publication n'est que le prologue.
La vraie automatisation, c'est d'automatiser aussi l'exploitation du jour où ça échoue.
