Un matin de septembre, huit galeries vidéo ont disparu d'un site que je maintiens. Pas de panne serveur, pas d'erreur PHP, pas de mise à jour hasardeuse. Un service tiers avait simplement décidé que le compte du client n'existait plus. Et il avait raison : la société qui l'avait ouvert n'existait plus non plus.
Le site est celui de Capsule 12, une agence vidéo de Wavre. Ses réalisations s'affichaient dans des galeries fournies par Elfsight, un service de widgets prêts à l'emploi. Le genre de brique qu'on installe en trois minutes et qu'on oublie pendant trois ans.
La console racontait tout en une ligne :
eapps.Platform throws: "Widget "353c6241-f8be-412b-b9ab-e792f52a9a88"
can`t be initialized because WIDGET_DISABLED"
Huit widgets, huit fois le même message. Le serveur d'Elfsight répondait, le script se chargeait correctement, mais il refusait de servir le contenu. Interrogé directement, leur point d'entrée était sans ambiguïté :
{
"status": 1,
"data": {
"widgets": {
"353c6241-f8be-412b-b9ab-e792f52a9a88": {
"status": 0,
"reason": "WIDGET_DISABLED"
}
}
}
}
1. Ce qu'on achète vraiment avec un plugin SaaS
Un widget hébergé, ce n'est pas du code qu'on installe. C'est un abonnement à un affichage. La nuance paraît théorique jusqu'au jour où elle devient le problème.
Sur ce site, les galeries tenaient dans quatre fichiers de 139 octets :
<script src="https://apps.elfsight.com/p/platform.js" defer></script>
<div class="elfsight-app-353c6241-f8be-412b-b9ab-e792f52a9a88"></div>
Deux lignes. Aucune donnée sur le serveur du client. Ni la liste des vidéos, ni l'ordre d'affichage, ni le nombre de colonnes, ni le comportement au clic. Tout vivait chez Elfsight, derrière un identifiant.
Quand le compte meurt, il ne reste rien à récupérer. J'ai essayé les trois voies possibles :
| Source | Ce que j'espérais | Résultat |
|---|---|---|
| API Elfsight | La configuration du widget | WIDGET_DISABLED |
| CDN Elfsight | Le code du widget, à rétro-analyser | HTTP 522 |
| Wayback Machine | Une capture de la page rendue | Aucune capture |
Trois portes, trois murs. Le rendu d'origine a finalement été reconstitué à partir d'une capture d'écran que le client avait prise avant la panne. C'est dire le niveau de récupération : une image, en guise de spécification.
2. Le compte n'était pas le nôtre
Voilà le vrai sujet. Le compte Elfsight avait été ouvert par une société prestataire, dissoute depuis. Ni le client, ni moi n'avions la main dessus. Pas de mot de passe oublié, pas de procédure de récupération : l'entité juridique propriétaire du compte n'existait plus.
C'est une dépendance qu'aucun audit technique ne détecte. Le code est propre, le site fonctionne, les performances sont bonnes. Rien ne signale que huit blocs de contenu dépendent d'un compte que personne dans la chaîne ne contrôle.
3. Reconstruire : trois voies, une seule tenable
Les vidéos étaient toutes sur le compte Vimeo du client, rangées dans quatre albums. La source de données existait donc, intacte. Restait à choisir comment y accéder.
L'API publique : séduisante, piégée
Vimeo expose une API v2 qui ne demande aucune authentification. Un appel, une liste de vidéos, pas de jeton à gérer. Tentant.
Deux tests l'ont écartée. D'abord la pagination :
page 1 : HTTP 200, 20 vidéos
page 2 : HTTP 200, 20 vidéos
page 3 : HTTP 200, 20 vidéos
page 4 : HTTP 403
page 5 : HTTP 403
Plafond dur à 60 vidéos par album. L'album principal en contient 100 : 42 vidéos seraient restées invisibles, sans le moindre message d'erreur. Un bug qui ne se voit pas, sur un site vitrine d'agence vidéo.
Ensuite, le comportement sur identifiant invalide. J'ai interrogé un album inexistant :
curl "https://vimeo.com/api/v2/album/9999999/videos.json"
→ HTTP 200, 2 vidéos
→ propriétaire : "Presley Media"
Pas une erreur : les vidéos d'un autre compte. Une faute de frappe dans un identifiant, et le site d'un client affiche le catalogue d'un inconnu. Vimeo documente d'ailleurs cette API comme non maintenue.
oEmbed : le bon outil, le mauvais usage
C'est la voie que Vimeo recommande en remplacement. Elle fonctionne parfaitement pour intégrer une vidéo précise, mais ne sait pas lister le contenu d'un album. Interrogée sur l'URL d'un album, elle le décrit comme un embed unique, pas comme une collection. Écartée.
L'API officielle : un jeton, mais le bon
L'API v3 exige une authentification. C'est exactement ce qu'on voulait éviter au départ, et c'est pourtant la seule option défendable, pour une raison qui n'a rien de technique : le jeton se crée depuis le compte Vimeo du client.
Une application déclarée sur son compte, en portée lecture seule sur du contenu déjà public. Le jeton lui appartient. S'il change de prestataire demain, il garde la main. Le scénario Elfsight devient structurellement impossible.
Résultat au premier appel :
album 8716475 : 100 vidéos sur 100, en un seul appel
vignettes disponibles : 100, 200, 295, 640, 960, 1280, 1920 px
4. Le module : 542 lignes contre deux
Les deux lignes d'Elfsight sont devenues un fichier de 542 lignes dans le thème. C'est le prix de l'autonomie, et il reste modeste au regard de ce qu'on récupère.
Le module fait trois choses qu'un widget hébergé ne fait pas :
- Il met en cache - six heures en transient, plus un miroir permanent en base. Si l'API Vimeo tombe, le site continue d'afficher le dernier contenu connu au lieu d'une page vide.
- Il se méfie de sa source - si le nombre de vidéos chute sous le tiers de l'effectif connu, il conserve l'ancien contenu. C'est la parade directe à l'échec silencieux constaté sur l'API publique.
- Il rend côté serveur - le HTML contient les vignettes dès le premier octet. Google voit les vidéos, ce qui n'était pas le cas avec Elfsight qui injectait tout en JavaScript après coup.
Ce dernier point mérite qu'on s'y arrête. Pendant des années, le contenu le plus valorisant de ce site - cent réalisations vidéo - était strictement invisible pour les moteurs de recherche. Le remplacement d'un plugin défaillant a réglé au passage un problème de référencement que personne n'avait identifié comme tel.
5. Le piège du remplaçant
Module déployé, galeries fonctionnelles, tests au vert. Puis un clic sur une vignette, et ceci :
Veuillez accepter le consentement des cookies
CookieYes, le gestionnaire de bandeau cookies du site, bloquait le lecteur Vimeo. Un bandeau noir en plein milieu de la grille, sans bouton, sans issue. Le visiteur clique sur une vidéo, il obtient un mur.
En inspectant sa configuration, le mécanisme apparaît :
_providersToBlock : [
{ url: "vimeo.com", categories: ["analytics"] },
...
]
Vimeo était classé en catégorie analytics à cause d'un cookie de suivi, vuid. Sauf que le lecteur était appelé avec le paramètre dnt=1, le mode « ne pas suivre » de Vimeo. J'ai mesuré ce qu'il déposait réellement :
| Cookie | Sans dnt | Avec dnt=1 |
|---|---|---|
vuid (suivi) | présent | absent |
player | présent | absent |
COOKIE_ID_PICOX_ID | présent | absent |
__cf_bm (technique) | présent | présent |
Un seul cookie subsiste, celui de protection anti-robots de Cloudflare, exempté de consentement. Le blocage n'avait plus d'objet : CookieYes protégeait le visiteur d'un traceur qui n'existait plus.
Deux contournements techniques fonctionnaient. L'attribut data-cky-tag, et surtout l'iframe imbriquée en srcdoc, qui passait sous le radar de leur détecteur. Je ne les ai pas retenus. Contourner un outil de conformité, c'est mettre le client en porte-à -faux le jour d'un contrôle, pour économiser cinq minutes de configuration.
La correction propre tenait en une ligne : retirer vuid de la déclaration, sur le compte CookieYes du client. Déclarer un cookie qui n'est plus déposé fausse la déclaration autant que d'en omettre un.
6. Ce que ça coûte, ce que ça rapporte
Trois heures de travail, diagnostic et tests compris. En face, un abonnement Elfsight à 260 euros par an, désormais inutile.
D'un côté une facture unique, de l'autre un loyer qui court. Le développement est amorti en neuf mois ; au-delà , le client garde les 260 euros dans sa poche chaque année, sans rien à renouveler.
Mais l'économie n'est pas l'essentiel. Ce qui change vraiment, c'est la structure de la dépendance :
| Avant | Après | |
|---|---|---|
| Propriétaire du compte | Société tierce dissoute | Le client |
| Données du site | Chez le prestataire | Sur le serveur du client |
| Si le service tombe | Page vide | Dernier contenu connu |
| Visible par Google | Non | Oui |
| Coût récurrent | 260 euros/an | 0 |
Et pour le client, rien ne change au quotidien : il continue de déposer ses vidéos dans l'album Vimeo correspondant, elles apparaissent sur le site dans les six heures. C'était la contrainte principale, elle est tenue.
Ce que j'en retiens
- Un plugin SaaS n'est pas une brique, c'est un locataire. Il occupe une place dans votre page sans jamais vous appartenir. Tant qu'il paie son loyer, tout va bien.
- La dépendance dangereuse n'est pas technique, elle est juridique. Ce n'est pas le service qui a lâché, c'est la société qui détenait le compte. Aucun audit de code ne détecte ça.
- Le jeton du client vaut mieux que pas de jeton du tout. L'API sans authentification paraissait plus simple ; elle amputait le catalogue de 42 vidéos et pouvait afficher le contenu d'un inconnu.
- Un remplacement bien fait répare plus que la panne. Cent vidéos sont devenues visibles par Google au passage, sans que ce soit l'objectif.
- Contourner un outil de conformité n'est jamais une solution. Ça fonctionne, c'est rapide, et ça reporte le risque sur le client.
Trois heures pour remplacer deux lignes de code. Dit comme ça, c'est cher. Mais ces deux lignes étaient le seul lien entre un site vitrine et cent réalisations, et ce lien appartenait à une société morte.