One September morning, eight video galleries vanished from a site I maintain. No server outage, no PHP error, no reckless update. A third-party service had simply decided the client's account no longer existed. And it was right: the company that opened it no longer existed either.
The site belongs to Capsule 12, a video agency near Brussels. Their work was displayed through galleries powered by Elfsight, a service selling ready-made widgets. The kind of building block you install in three minutes and forget about for three years.
The console told the whole story in one line:
eapps.Platform throws: "Widget "353c6241-f8be-412b-b9ab-e792f52a9a88"
can`t be initialized because WIDGET_DISABLED"
Eight widgets, the same message eight times. Elfsight's server was responding, the script loaded fine, but it refused to serve the content. Queried directly, their endpoint left no room for doubt:
{
"status": 1,
"data": {
"widgets": {
"353c6241-f8be-412b-b9ab-e792f52a9a88": {
"status": 0,
"reason": "WIDGET_DISABLED"
}
}
}
}
1. What you actually buy with a SaaS plugin
A hosted widget isn't code you install. It's a subscription to a display. The distinction sounds academic until the day it becomes the problem.
On this site, the galleries fit into four 139-byte files:
<script src="https://apps.elfsight.com/p/platform.js" defer></script>
<div class="elfsight-app-353c6241-f8be-412b-b9ab-e792f52a9a88"></div>
Two lines. Not a single piece of data on the client's server. Not the video list, not the display order, not the column count, not the click behaviour. Everything lived at Elfsight, behind an identifier.
When the account dies, there's nothing left to recover. I tried all three possible routes:
| Source | What I hoped for | Result |
|---|---|---|
| Elfsight API | The widget configuration | WIDGET_DISABLED |
| Elfsight CDN | The widget code, to reverse-engineer | HTTP 522 |
| Wayback Machine | A snapshot of the rendered page | No snapshot |
Three doors, three walls. The original layout was eventually rebuilt from a screenshot the client had taken before the outage. That tells you how much was recoverable: one image, serving as the spec.
2. The account was never ours
Here's the real subject. The Elfsight account had been opened by a contractor, since dissolved. Neither the client nor I had any control over it. No forgotten password, no recovery flow: the legal entity that owned the account had ceased to exist.
This is a dependency no technical audit catches. The code is clean, the site works, performance is fine. Nothing signals that eight content blocks hang on an account nobody in the chain controls.
3. Rebuilding: three routes, only one viable
The videos were all on the client's Vimeo account, organised into four albums. The data source existed, untouched. What remained was choosing how to reach it.
The public API: tempting, booby-trapped
Vimeo exposes a v2 API requiring no authentication. One call, a video list, no token to manage. Tempting.
Two tests ruled it out. First, pagination:
page 1 : HTTP 200, 20 videos
page 2 : HTTP 200, 20 videos
page 3 : HTTP 200, 20 videos
page 4 : HTTP 403
page 5 : HTTP 403
Hard ceiling at 60 videos per album. The main album holds 100: 42 videos would have stayed invisible, without a single error message. A bug you cannot see, on the showcase site of a video agency.
Then, the behaviour on an invalid identifier. I queried a non-existent album:
curl "https://vimeo.com/api/v2/album/9999999/videos.json"
→ HTTP 200, 2 videos
→ owner: "Presley Media"
Not an error: another account's videos. One typo in an identifier, and a client's site displays a stranger's catalogue. Vimeo also documents this API as unmaintained.
oEmbed: right tool, wrong job
This is the route Vimeo recommends as a replacement. It works perfectly for embedding a specific video, but cannot list an album's contents. Queried on an album URL, it describes it as a single embed rather than a collection. Ruled out.
The official API: a token, but the right one
The v3 API requires authentication. That's exactly what we wanted to avoid, and it's still the only defensible option, for a reason that has nothing to do with technology: the token is created from the client's own Vimeo account.
An application declared on their account, scoped read-only on already-public content. The token belongs to them. If they switch contractors tomorrow, they keep control. The Elfsight scenario becomes structurally impossible.
Result on the first call:
album 8716475 : 100 videos out of 100, in a single call
available thumbnails: 100, 200, 295, 640, 960, 1280, 1920 px
4. The module: 542 lines against two
Elfsight's two lines became a 542-line file in the theme. That's the price of independence, and it stays modest given what you get back.
The module does three things a hosted widget does not:
- It caches - six hours in a transient, plus a permanent mirror in the database. If the Vimeo API goes down, the site keeps showing the last known content instead of an empty page.
- It distrusts its source - if the video count drops below a third of the known total, it keeps the previous content. That's the direct countermeasure to the silent failure seen on the public API.
- It renders server-side - the HTML carries the thumbnails from the very first byte. Google sees the videos, which wasn't the case with Elfsight injecting everything in JavaScript after the fact.
That last point deserves a pause. For years, this site's most valuable content - a hundred video productions - was strictly invisible to search engines. Replacing a broken plugin fixed an SEO problem nobody had identified as one.
5. The replacement's trap
Module deployed, galleries working, tests green. Then a click on a thumbnail, and this:
Please accept cookie consent
CookieYes, the site's cookie banner manager, was blocking the Vimeo player. A black panel in the middle of the grid, no button, no way out. The visitor clicks a video, they hit a wall.
Inspecting its configuration, the mechanism shows up:
_providersToBlock : [
{ url: "vimeo.com", categories: ["analytics"] },
...
]
Vimeo was filed under analytics because of a tracking cookie, vuid. Except the player was called with the dnt=1 parameter, Vimeo's do-not-track mode. I measured what it actually dropped:
| Cookie | Without dnt | With dnt=1 |
|---|---|---|
vuid (tracking) | present | absent |
player | present | absent |
COOKIE_ID_PICOX_ID | present | absent |
__cf_bm (technical) | present | present |
One cookie remains, Cloudflare's bot-protection cookie, exempt from consent. The block had lost its purpose: CookieYes was shielding visitors from a tracker that no longer existed.
Two technical workarounds did the job. The data-cky-tag attribute, and above all the nested iframe in srcdoc, which slipped past their detector. I kept neither. Working around a compliance tool means exposing the client on the day of an audit, to save five minutes of configuration.
The clean fix was one line: remove vuid from the declaration, on the client's CookieYes account. Declaring a cookie that is no longer dropped distorts the declaration just as much as omitting one.
6. What it costs, what it returns
Three hours of work, diagnosis and testing included. Against it, an Elfsight subscription at 260 euros a year, now pointless.
A one-off invoice on one side, a running rent on the other. The build pays for itself in nine months; beyond that, the client keeps those 260 euros every year, with nothing to renew.
But the saving isn't the point. What genuinely changes is the structure of the dependency:
| Before | After | |
|---|---|---|
| Account owner | Dissolved third party | The client |
| Site data | At the provider | On the client's server |
| If the service goes down | Empty page | Last known content |
| Visible to Google | No | Yes |
| Recurring cost | 260 euros/year | 0 |
And for the client, daily life doesn't change: they keep dropping videos into the matching Vimeo album, and they show up on the site within six hours. That was the main constraint, and it holds.
What I take away from it
- A SaaS plugin isn't a building block, it's a tenant. It occupies space in your page without ever belonging to you. As long as it pays its rent, all is well.
- The dangerous dependency isn't technical, it's legal. The service didn't fail, the company holding the account did. No code audit catches that.
- The client's token beats no token at all. The unauthenticated API looked simpler; it cut 42 videos from the catalogue and could display a stranger's content.
- A replacement done right fixes more than the outage. A hundred videos became visible to Google along the way, without that being the goal.
- Working around a compliance tool is never a solution. It works, it's fast, and it shifts the risk onto the client.
Three hours to replace two lines of code. Put that way, it sounds expensive. But those two lines were the only link between a showcase site and a hundred productions, and that link belonged to a dead company.