source.unsplash.com ist verschwunden: Der Post-Mortem und alle Wege, es zu ersetzen

2021 abgekündigt mit „bestehende Verwendungen funktionieren weiter“, im Juni 2024 abgeschaltet, und wird bis heute in neuen Code geschrieben. Der nüchterne Post-Mortem — und die drei Ersatzlösungen, inklusive Proxy, der die schlüssellose Zufälligkeit zurückbringt.

Ein Schwarz-Weiß-Foto eines Smartphones mit gesprungenem Display auf einer hellen Holzoberfläche, auf dem beschädigten Display ist das Unsplash-Logo zu sehen.
Foto über Unsplash

Ein Stockfoto-Dienst hat eine Subdomain abgeschaltet, und zwei Jahre später bricht sie immer noch Dokumentationsseiten, Login-Bildschirme, Kursübungen und frisch generierten Code. Dies ist ein Post-Mortem einer URL — was sie tat, was sie umgebracht hat, und was an ihre Stelle gehört — plus ein nüchterner Blick auf den seltsameren Teil der Geschichte: Die Maschinen, die unseren Code schreiben, haben nicht bemerkt, dass sie verschwunden ist.

Die HTTP-Antworten, die beiden Wort-für-Wort zitierten Changelog-Einträge, die API-Limits, die Issue-Tracker der betroffenen Projekte sowie die Zählungen von GitHub, npm und Stack Overflow stammen allesamt aus Primärquellen, mit der Methode für jede einzelne in den Fußnoten. Wer nur die Lösung sucht, springt direkt zu der Migrationstabelle.

Was man heute bekommt, wenn man es trotzdem anfragt

Ein Befehl, kein Schlüssel, reproduzierbar von jeder beliebigen Maschine aus:

terminal
curl -I https://source.unsplash.com/random

HTTP/2 503
cache-control: no-cache, no-store
content-type: text/html; charset=utf-8
server: Heroku
via: 2.0 heroku-router
# body: ein iframe, das auf herokucdn.com/error-pages/application-error.html zeigt

Hier liegt kein DNS-Fehler vor. source.unsplash.com lässt sich weiterhin auflösen — es ist ein CNAME auf einen herokudns.com-Host —, die Anfrage wird also beantwortet, nur eben nicht von einer Anwendung. Dieses Detail ist wichtiger, als es klingt: Ein Browser, der ein schnelles 503 mit HTML-Body erhält, rendert einen kaputten Bild-Platzhalter, und jeder Code, der response.ok oder einen onerror-Handler abfragt, den man nie geschrieben hat, läuft in genau den Fehlerpfad, den man nie getestet hat.

URL-Muster Was früher zurückkam Heute
source.unsplash.com/randomEin zufälliges Foto, jede Größe503
source.unsplash.com/random/1600x900Ein zufälliges Foto, auf Größe zugeschnitten503
source.unsplash.com/1600x900/?apple,deskEin zufälliges Foto passend zu Suchbegriffen503
source.unsplash.com/featured/1600x900?natureEin zufälliges featured-Foto503
source.unsplash.com/collection/190727/800x600Ein zufälliges Foto aus einer Collection503
source.unsplash.com/user/scottwebb/1600x900Ein zufälliges Foto eines Fotografen503
source.unsplash.com/dailyDas Foto des Tages503

Einzeln geprüft mit curl -o /dev/null -w "%{http_code}". Die Suchfunktion wurde, wie angekündigt, zuerst zurückgefahren; heute ist die gesamte Anwendung abgeschaltet, sodass diese Unterscheidung nicht mehr existiert.

Drei Jahre zwischen „deprecated“ und „aus“

Beide Ankündigungen sind weiterhin lesbar, an einem Ort, unter unsplash.com/documentation/changelog. Vollständig zitiert, weil der Wortlaut die ganze Geschichte erzählt:

25. November 2021 — „Unsplash Source being deprecated“
„Unsplash Source is being deprecated. Existing uses will continue to work, however for new projects use the full Unsplash API.“

11. Juni 2024 — „Unsplash Source sunset“
„Unsplash Source has been officially unsupported since its deprecation in 2021. As part of the final sunsetting, we will first wind down by disabling the search feature, and in the coming weeks turn off the application entirely. Existing uses of Source — particularly production-level ones — should migrate as soon as possible to the full Unsplash API.“

Liest man beide nacheinander, wird das Fehlermuster offensichtlich. Die Mitteilung von 2021 enthielt ein Versprechen (existing uses will continue to work) und kein Datum. Ein Entwickler, der sie 2021 las, hatte jeden Grund, funktionierenden Code unangetastet zu lassen; ein Entwickler, der 2022 dazustieß, hat sie nie gelesen. Die Mitteilung von 2024 nannte „the coming weeks“ — drei Jahre später, auf einer Seite, die niemand als Lesezeichen gesetzt hatte.

Unsplash veröffentlicht tatsächlich eine Deprecation-Policy, und sie ist durchaus vernünftig — die Dokumentation besagt, dass Änderungen an öffentlich dokumentierten Feldern und Endpunkten im Changelog mit mindestens 3 Wochen Vorlauf angekündigt werden und Endpunkte während der Deprecation-Phase einen Warning-Header zurückgeben. Derselbe Absatz enthält den Satz, der erklärt, warum davon nichts Source schützte: „For any non-publicly documented fields or endpoints, we may make changes to these with no warning.“ Source war nie ein Endpunkt der dokumentierten API. Es lag außerhalb der Policy, die es hätte abdecken können.

  • Die praktische Lehre lautet nicht „Unsplash war nachlässig“. Sie lautet: Eine URL, die man ohne jede Dokumentation nutzen kann, ist auch eine URL, deren Deprecation-Policy man nicht gelesen hat.
  • Der Ausfall ging der Ankündigung voraus. Ein am 28. November 2022 eingereichtes Drupal-Issue berichtet bereits „I get always a Heroku application error“ — achtzehn Monate vor dem Sunset-Eintrag. So sterben diese Dienste: langsam, dann in einer Ankündigung, die man nie zu Gesicht bekommt.

Die Ankündigung ist schwerer zu finden als der Ausfall

Die Deprecation von 2021 wurde auf changelog.unsplash.com veröffentlicht, und genau auf diese URL verweist jeder zeitgenössische Bugreport — einschließlich des Drupal-Issues oben. Drei Messungen:

  1. Der HTTPS-Endpunkt ist defekt. openssl s_client -connect changelog.unsplash.com:443 liefert tlsv1 alert internal error — der Handshake scheitert, bevor überhaupt ein Zertifikat präsentiert wird. Jeder Link aus der 2021er-Ära, der https:// nutzte, ist damit im Browser tot.
  2. Über reines HTTP wird umgeleitet, aber nicht nützlich. Folgt man http://changelog.unsplash.com/deprecations/2021/11/25/source-deprecation.html, landet man zwei Hops später bei einem 400 unter unsplash.com/@documentation/changelog/deprecations/2021/11/25/source-deprecation/html — der Pfad wurde von der Username-Route der Seite verschluckt.
  3. Das Archiv hat genau dort ein Loch, wo der Sunset liegt. Der letzte erfolgreiche Snapshot des alten Changelogs in der Wayback Machine stammt vom 24. März 2024; der erste Snapshot des neuen vom 23. August 2024. Der Sunset wurde am 11. Juni 2024 angekündigt — innerhalb dieser fünfmonatigen Lücke.

Nichts davon ist eine Verschwörung; es ist eine gewöhnliche CMS-Migration. Aber die Konsequenz ist real, und sie ist der Grund, warum dieser Artikel beide Einträge vollständig zitiert: Die Primärquelle einer Deprecation sollte länger existieren als das, was sie deprecatet — und hier wäre das beinahe nicht der Fall gewesen.

Was tatsächlich kaputtging

Keine Nebenprojekte. Die folgenden Ausfälle sind öffentliche Issue-Tracker-Einträge; Titel, Daten und Status stammen aus den APIs von GitHub und drupal.org.

Projekt Issue Eröffnet Was es besagt
MUI (Material UI) #42736 24. Jun. 2024 „[docs] Random Unsplash photo URL is no longer functional“ — das offizielle Sign-in side-Template lieferte ein totes Bild aus. Drei Tage später geschlossen.
Nextcloud #115 17. Jan. 2023 „Migrate to Unsplash API“ — die Hintergrund-App war auf Source-URIs aufgebaut. Achtzehn Monate offen, geschlossen am 16. Juli 2024.
sindresorhus/Actions #248 28. Mai 2024 „Get Unsplash Image: 503 Error“ — eine iOS/macOS-Shortcuts-Action, kaputt zwei Wochen vor Ankündigung des Sunsets.
Drupal — Gin Login #3324054 28. Nov. 2022 „Unsplash has deprecated source.unsplash.com — this delays reCAPTCHA from loading, preventing users from logging in.“

Diese letzte Zeile lohnt eine zweite Lektüre, denn sie ist es, die man sich einprägen sollte. Ein dekoratives Bild neben einem Login-Formular — das offenkundig unkritischste Asset auf der Seite — verschlechterte sich zu einem Authentifizierungsausfall, weil eine langsame Drittanbieter- Anfrage vor dem CAPTCHA hing, das das Login-Formular benötigte. Niemand hat es so geplant. Es entstand aus der Reihenfolge, in der ein Browser Dinge lädt.

Ihr Coding-Assistent hat die Mitteilung nicht bekommen

Hier kommt der Teil, der aus einem Ausfall von 2024 ein Problem von 2026 macht. source.unsplash.com wurde etwa acht Jahre lang dokumentiert, gebloggt, gelehrt und kopiert. All dieser Text steckt in den Trainingsdaten der Modelle, die heute unseren Starter-Code schreiben — und Text verfällt nicht. Drei Zählungen:

MessungWert am 30. Aug. 2026Wie erhoben
Dateien mit source.unsplash.com 3.344 GitHub-Codesuch-API, q=source.unsplash.com (nur indexierter öffentlicher Code — eine Untergrenze, keine Gesamtzahl)
Repositories in einer 100-Dateien-Stichprobe, erstellt nach dem Sunset 12 von 77 Gleiche Query, 100 Ergebnisse, dedupliziert auf 77 Repositories, created_at verglichen mit 11. Jun. 2024
…und Repositories in dieser Stichprobe mit Pushes in den letzten 12 Monaten 20 von 77 Lebende Repositories, keine Archive — darunter elastic/kibana, dessen Demo-Datei noch imageUrl: 'https://source.unsplash.com/64x64/?dingo' enthält
Monatliche Downloads von unsplash-source-es6 23 npm-Registry-API — ein Wrapper für einen toten Dienst, zuletzt 2022 veröffentlicht, wird noch immer installiert
Stack-Overflow-Beiträge, die es erwähnen 1.459 Stack-Exchange-API, /search/excerpts, Gesamtsumme

Der direkteste Beleg liegt gar nicht im Anwendungscode — er liegt in Prompts. Das Top-Ergebnis dieser Suche ist eine Sammlung von GPT-Systemprompts mit der Zeile „please use unsplash API( https://source.unsplash.com/1280x720/?<PUT YOUR QUERY HERE>“. Diese Anweisung wird heute noch in neue Assistenten hineinkopiert. Das Modell überprüft die URL nicht; es wurde angewiesen, sie zu benutzen, und jedes Beispiel, das es je gesehen hat, stimmte damit überein.

Der Fehler in generiertem Code hat also zwei unabhängige Ursachen, und die eine zu beheben behebt nicht die andere: veraltete Trainingsdaten und veraltete, von Menschen darauf aufbauende Anweisungen. So oder so ist das Symptom dieselbe Familie von Bildern, die nie laden:

die toten Bild-Muster, nach denen sich Greppen lohnt
source.unsplash.com/random/1200x800   # 503 seit Mitte 2024 — kommt nie zurück
images.unsplash.com/photo-…           # echtes CDN, aber gemerkte IDs existieren vielleicht nicht
via.placeholder.com/400               # graues Rechteck, in Produktion ausgeliefert
placehold.co/800x600                  # graues Rechteck, mit Absicht
picsum.photos/800/600                 # ein echtes Foto, ohne Bezug zur Seite
/placeholder.png                      # eine Datei, die nie ins Repo aufgenommen wurde

Eine Fußnote zur zweiten Zeile dieser Liste: Beim Schreiben dieses Artikels vollzog auch via.placeholder.com von unserem Testnetz aus keinen TLS-Handshake und antwortete über reines HTTP mit 403. Prüfen Sie es im eigenen Netz, bevor Sie sich darauf verlassen — der Fallback, auf den diese Tools zurückgreifen, kann seine eigene Ausfallgeschichte haben.

Nur der erste dieser Fälle ist wirklich kaputt. Die anderen sind auf subtilere Weise schlimmer: Sie laden, das Layout wirkt fertig, und niemand bemerkt, dass die Seite mit nichts Bestimmtem bebildert ist. Und das alles ist nicht auf Bilder beschränkt — es ist die allgemeine Form des Problems. Das Bild eines Modells vom Web ist eine Momentaufnahme, und Endpunkte, CLI-Flags, Paketnamen und Gratis-Tarife bewegen sich weiter, nachdem der Verschluss zugeklappt ist.

Die Migrationstabelle

Es gibt genau drei Zielpunkte, und der ehrliche Weg, sie darzustellen, ist über das, was man aufgibt. Zuerst die Spalte wählen, dann die eigene Zeile lesen.

Alte Source-URL A. Feste CDN-URLkein Schlüssel · keine Zufälligkeit B. Unsplash-APISchlüssel · serverseitiger Aufruf C. Eigener ProxySchlüssel verborgen · Zufälligkeit zurück
/random images.unsplash.com/photo-… — ein selbst gewähltes Foto GET /photos/random /?w=1600
/random/1600x900 …?w=1600&h=900&fit=crop /photos/random + Imgix-Parameter auf der zurückgegebenen URL /?w=1600&h=900&fit=crop
/1600x900/?apple,desk Kein Äquivalent — Foto manuell auswählen /photos/random?query=apple,desk /?query=apple,desk&w=1600
/featured/1600x900?nature Kein Äquivalent /photos/random?query=nature für „featured“ gibt es keinen Nachfolger /?query=nature&w=1600
/collection/67920491/1600x900 Kein Äquivalent /photos/random?collections=67920491 /?collections=67920491&w=1600
/user/scottwebb/1600x900 Kein Äquivalent /photos/random?username=scottwebb /?username=scottwebb&w=1600
/daily Ein Foto fixieren, im Build rotieren Kein Äquivalent — ein zufälliges Foto selbst 24 h lang cachen Dasselbe, mit dem Cache im Proxy

Option A ist die, die die meisten eigentlich wollen. War das Bild dekorativ — ein Hero, ein seitliches Login-Panel, ein Card-Hintergrund —, brauchte man nie ein anderes Foto pro Anfrage. Eines wählen, die CDN-URL behalten, und die Seite hängt von nichts Zufälligem mehr ab:

eine feste, größenveränderbare Unsplash-URL — kein Schlüssel, kein API-Aufruf
<img src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1600&h=900&fit=crop&auto=format"
     width="1600" height="900" alt="…">
# Offiziell unterstützte Parameter: w, h, crop, fit, fm, auto=format, q, dpr.
# Jeden ixid-Parameter behalten, den die API geliefert hat — er meldet den View.

Option B ist der offizielle Weg, und dabei verlagert sich der Aufruf auf die Serverseite, weil ein Client-ID im Frontend-JavaScript eine veröffentlichte Anmeldeinformation ist. Zwei Regeln, an denen sich viele stoßen: collections/ topics lassen sich nicht mit query in derselben Anfrage kombinieren, und count (max. 30) ändert die Antwortform in ein Array, selbst wenn es 1 ist.

der offizielle Ersatz für /random
curl "https://api.unsplash.com/photos/random?query=nature&orientation=landscape" \
  -H "Authorization: Client-ID YOUR_ACCESS_KEY" \
  -H "Accept-Version: v1"

# → JSON. Das Bild liegt unter .urls.regular / .urls.raw (w/h/fit selbst ergänzen).
# → X-Ratelimit-Limit: 1000   X-Ratelimit-Remaining: 999

Option C: Source nachbauen, in rund vierzig Zeilen

Ging es tatsächlich um das Verhalten — eine schlüssellose URL, die jedes Mal ein anderes Foto liefert, direkt aus einem <img>-Tag, in einem CMS-Feld oder auf einer statischen Seite ohne Server nutzbar — dann muss man diesen Endpunkt selbst betreiben. Es ist ein kleiner Worker vor der API, und die drei Dinge, die dafür sorgen, dass er den Kontakt mit der Produktion überlebt, sind der Cache, die Referrer-Prüfung und das Durchreichen des restlichen Query-Strings an das CDN.

worker.js — ein schlüsselloser, Source-förmiger Endpunkt auf /photos/random
// Cloudflare Workers. Anderswo (Deno Deploy, Val Town…) ist die Form dieselbe,
// aber einen benannten Cache mit caches.open() öffnen statt caches.default.
// UNSPLASH_KEY bleibt serverseitig. Aufrufer sehen ihn nie.
const ALLOWED = ["example.com", "www.example.com"];   // nur eigene Domains
const API_PARAMS = ["query", "collections", "topics", "username", "orientation"];
const TTL = 60;                                       // Sekunden — schützt das Stunden-Kontingent

const host = (value) => { try { return new URL(value).hostname; } catch { return null; } };

export default {
  async fetch(req, env, ctx) {
    // 0. Nur GET: Die Cache-API verweigert das Speichern von allem anderen, und ein
    //    Bild-Endpunkt hat ohnehin kein anderes Verb zu beantworten.
    if (req.method !== "GET")
      return new Response("Method not allowed", { status: 405 });
    const url = new URL(req.url);

    // 1. Nur eigene Seiten dürfen einbetten — ein öffentlicher Zufallsbild-Endpunkt
    //    im offenen Internet ist fremdes Rate-Limit, das man verbrennt.
    const ref = req.headers.get("referer");       // fehlt bei vielen legitimen Clients
    if (ref && !ALLOWED.includes(host(ref)))
      return new Response("Forbidden", { status: 403 });

    // 2. Pro Parameterkombination cachen, damit eine Seite mit 12 Bildern
    //    einen API-Aufruf pro Minute kostet statt zwölf pro Render.
    const cache = caches.default;
    const hit = await cache.match(req);
    if (hit) return hit;

    // 3. Die offizielle API nach einem Zufallsfoto fragen.
    const api = new URL("https://api.unsplash.com/photos/random");
    for (const p of API_PARAMS)
      if (url.searchParams.has(p)) api.searchParams.set(p, url.searchParams.get(p));

    const r = await fetch(api, { headers: {
      Authorization: "Client-ID " + env.UNSPLASH_KEY,
      "Accept-Version": "v1",
    }});
    // 403 hier bedeutet meist das Stunden-Kontingent, nicht einen falschen Schlüssel — TTL erhöhen, nicht in Panik geraten.
    if (!r.ok) return new Response("Upstream " + r.status, { status: 502 });
    const photo = await r.json();

    // 4. Bild-URL neu aufbauen: ixid behalten, die Sizing-Parameter des Aufrufers anhängen.
    const img = new URL(photo.urls.raw);          // .raw trägt ixid bereits mit sich
    for (const [k, v] of url.searchParams)
      if (!API_PARAMS.includes(k)) img.searchParams.set(k, v);  // w, h, fit, q…

    const res = new Response(null, { status: 302, headers: {
      Location: img.toString(),
      "Cache-Control": "public, max-age=" + TTL,
      // Credit reist mit dem Redirect; Header-Werte müssen ASCII sein, daher die Kodierung.
      "X-Photo-Credit": encodeURIComponent(photo.user.name + " on Unsplash"),
      "X-Photo-Link": photo.links.html,
    }});
    ctx.waitUntil(cache.put(req, res.clone()));
    return res;
  },
};

Eine URL zu migrieren wird damit zu Suchen-und-Ersetzen — und genau das macht diese Option die zwanzig Minuten wert:

1:1-Ersetzung
- https://source.unsplash.com/collection/67920491/1600x900
+ https://img.example.com/?collections=67920491&w=1600&h=900&fit=crop

Zwei Design-Hinweise, die beide erst nach einem schlechten Nachmittag jemandem aufgefallen sind. Der Redirect (302) statt des Durchreichens der Bytes hält Bandbreitenkosten von Ihnen fern und sorgt dafür, dass der View weiterhin über Unsplashs CDN gezählt wird, was die Richtlinien verlangen. Und die Referer-Prüfung ist absichtlich nachsichtig, wenn der Header fehlt — viele legitime Clients entfernen ihn —, verhindert aber trotzdem den offensichtlichen Fall, dass der eigene Endpunkt zur kostenlosen Bild-API für Dritte wird.

Die Regeln, die man mit der API erbt

Source hatte keine Regeln, weil es kein Konto gab. Die API hat fünf, die die Architektur des Ganzen verändern — allesamt aus der aktuellen Dokumentation:

  • Rate-Limits gelten pro Stunde und sind anfangs klein. 50 Anfragen/Stunde im Demo-Modus; 1.000/Stunde, sobald die Anwendung für Produktion freigegeben wurde. Nur Aufrufe an api.unsplash.com zählen — Bildanfragen an images.unsplash.com nicht. X-Ratelimit-Remaining bei jeder Antwort lesen.
  • Hotlinking ist Pflicht, nicht nur erlaubt. Unsplash verlangt, dass die von der API zurückgegebenen Bild-URLs direkt eingebettet werden, damit Fotoaufrufe dem Fotografen zugeordnet werden können. Die Datei auf ein eigenes CDN zu spiegeln, ist die eine Optimierung, die nicht frei steht.
  • Den ixid-Parameter behalten. Größenänderung und Zuschnitt der zurückgegebenen URL sind vorgesehen; das Entfernen des Parameters, der die Anwendung identifiziert, nicht.
  • Attribution und Download-Tracking gehören zur Vereinbarung — Fotograf und Unsplash werden genannt, und ein „Download“ wird über den Download-Endpunkt des Fotos gemeldet, sobald ein Nutzer die Datei bezieht — ein Ereignis, das man selbst auslösen muss.
  • Verteilte Produkte brauchen dynamische Client-Registrierung. Wer ein Plugin, ein Theme oder ein selbstgehostetes CMS ausliefert, für den ist ein gemeinsam genutzter Schlüssel sowohl ein Verstoß gegen die Policy als auch ein Single Point of Failure; die API hat für genau diesen Fall einen Registrierungsablauf.

Hier lohnt Ehrlichkeit über den Umfang: Wer ohnehin einen API-Schlüssel verdrahtet, dem steht auch die Wahl offen, welche Bild-API es sein soll — und es lohnt sich, dafür fünf Minuten aufzuwenden, bevor der Client geschrieben wird. Wir haben die kostenlosen verglichen — Kontingente, Regeln, Suchverhalten und Antwortformen — in dem Vergleich kostenloser Stockfoto-APIs.

Wer nur einen Platzhalter wollte, sollte das auch sagen

Ein großer Teil der Source-Nutzung hatte nie etwas mit Unsplash im engeren Sinn zu tun. Es ging um „irgendetwas Bildförmiges hierhin, während ich das Layout baue“. Dafür gibt es weiterhin schlüssellose Dienste, und sie sind die richtige Antwort:

DienstSchlüssel?Was man bekommtWo es endet
Lorem Picsum Nein Echte Fotografien: picsum.photos/800/600, ein stabiles mit /id/237/… oder /seed/xxx/…, dazu ?grayscale und ?blur=1..10. Der Endpunkt /v2/list nennt zu jedem Foto Unsplash-Seite und Urheber. Kein Subject-Targeting. Das Foto hat keinen Bezug zur eigenen Seite.
placehold.co Nein Beschriftete Rechtecke in jeder Größe — ehrlicher Wireframe-Füller. Es ist eine graue Box, und sieht auch in einem Screenshot für den Kunden so aus.
Openverse Nein Ein offen lizenzierter Katalog mit öffentlicher API, betrieben von WordPress.org. Schlüsselwort-Matching, und Lizenzen variieren pro Element — man muss sie lesen.

Die entscheidende Unterscheidung: Ein Platzhalter ist per Definition vorübergehend. Übersteht das Bild bis in die Produktion, ist es kein Platzhalter mehr — es ist eine Illustration, die niemand ausgewählt hat, und das merkt man ihr an.

Ein Schlüssel statt drei

Hier ist der Teil der Migration, mit dem niemand plant: Wer Source verlässt, landet selten bei einer API. Eine Seite braucht einen Hero, zwei Sektionsbilder und etwas für ein Card-Grid, und die ehrliche Antwort ist meist Unsplash plus Pexels plus Pixabay — drei Registrierungen, drei Auth-Schemata, drei JSON-Formen, drei Paginierungsmodelle und drei Sätze von Attributionsregeln, alles um dieselben <img>-Tags zu füllen. Diese Integrations- arbeit ist die eigentliche Rechnung für eine verschwindende schlüssellose URL, und sie kommt Wochen nach dem Ausfall, der sie ausgelöst hat.

Genau dafür haben wir Pexafy gebaut: einen einzigen Schlüssel für 9 Bibliotheken mit freien Lizenzen in einem Schema, mit satzweiser semantischer Suche — sodass eine vollständige Beschreibung wie „ein gesprungenes Handy-Display auf einem Holztisch, von oben fotografiert“ gerankte Ergebnisse liefert statt nichts. Zwei Grenzen, klar benannt, weil dieser ganze Artikel davon handelt, kein zweites Mal überrascht zu werden: Es braucht einen Schlüssel, stellt also nicht wieder her, was Source war — es gehört in dieselbe Kategorie wie die offizielle Unsplash-API oben; und es führt freilizenzierte Fotografie, keine redaktionellen oder Marken-Bilder.

Der wirklich neue Teil richtet sich an die Assistenten oben: Ein MCP-Server unter mcp.pexafy.com/mcp bedeutet, dass ein Modell, das sonst eine Bild-URL aus dem Gedächtnis zitieren würde, stattdessen einen echten Katalog durchsuchen und ein Foto zurückgeben kann, das existiert, samt zugehöriger Credit-Zeile. Das ist eine bessere Antwort auf maschinell geschriebene tote URLs als jede Lint-Regel, und die Überlegung dazu steht in Bildsuch- Infrastruktur für KI-Agenten.

Den eigenen Bestand in zehn Minuten prüfen

Egal wohin migriert wird — das hier zuerst tun: URLs, die man nicht gefunden hat, kann man nicht reparieren. Source ist nur das Beispiel von heute; dieselben drei Schritte gelten für jedes externe Asset, das eingebettet wird.

jede tote Referenz finden, dann draußen halten
# 1. Alles im Repo, einschließlich Docs, Tests, Fixtures und READMEs.
grep -rn --binary-files=without-match \
  -e "source.unsplash.com" -e "via.placeholder.com" -e "/placeholder.png" .

# 2. Alles, was die Datenbank enthält — CMS-Inhalte sind dort, wo sich das am längsten hält.
psql -c "SELECT id FROM posts WHERE body LIKE '%source.unsplash.com%'"

# 3. Alles, was die gebaute Seite tatsächlich anfragt: crawlen und Fehler auflisten.
#    Das Attribut abgleichen, nicht eine Dateiendung — Bild-URLs enden selten auf .jpg.
grep -rhoE 'src="[^"]+"' dist/ \
  | cut -d'"' -f2 | grep -E '^https?://' | sort -u \
  | xargs -P8 -I{} curl -s -o /dev/null -w "%{http_code} {}\n" {} \
  | grep -v "^200"

# 503 https://source.unsplash.com/random/1200x800   ← wonach Sie suchen

Dann einmalig festlegen, wie viel externe Bilder kosten dürfen. Vier Regeln, die den nächsten Shutdown überleben, egal wer ihn verursacht:

  1. Zur Build-Zeit abrufen, nicht zur Request-Zeit. Ein Bild, das während des Builds aufgelöst wird, scheitert in der CI, vor den Augen eines Entwicklers — nicht um 3 Uhr nachts vor den Augen eines Nutzers.
  2. Ein dekoratives Asset darf nie einen kritischen Pfad blockieren. Nichts Externes vor einem Login-Formular preloaden; jedem Drittanbieter-<img> einen onerror-Fallback sowie explizite width/height geben, damit ein Fehlschlag eine leere Box kostet, keinen Layout-Shift oder blockierten Skriptablauf.
  3. Die Prüfung in die CI einbauen. Schritt 3 oben, auf dem gebauten Output ausgeführt, macht aus „irgendjemand hat es irgendwann bemerkt“ einen roten Build. Das ist der einzige Schritt, der Wiederholungen verhindert.
  4. Externe Abhängigkeiten wie jede andere budgetieren. Festhalten, von welchen Hosts die eigenen Seiten abhängen dürfen und was passiert, wenn jeder einzelne ausfällt. Eine URL, für die man sich nicht registrieren musste, ist trotzdem eine Abhängigkeit — Source hat bewiesen, dass es einfach eine ist, die niemandem gehört.

Quellen & Fußnoten

1 Jeder Statuscode, jede Zahl und jede zitierte Zeile in diesem Artikel wurde am 30. August 2026 aus der jeweiligen Primärquelle entnommen. HTTP-Statuscodes wurden mit curl gegen jedes URL-Muster ermittelt; alle lieferten 503 mit server: Heroku und einem Body, der herokucdn.com/error-pages/application-error.html einbettet. Die DNS-Auflösung wurde am selben Tag bestätigt (ein CNAME auf einen herokudns.com-Host).

2 Beide Changelog-Einträge sind wörtlich zitiert aus unsplash.com/documentation/changelog. Der Wortlaut der Deprecation-Policy (3 Wochen Vorlauf, Warning-Header und die Ausnahme für nicht öffentlich dokumentierte Endpunkte) stammt aus unsplash.com/documentation, vom selben Tag.

3 Der TLS-Fehler wurde reproduziert mit openssl s_client -connect changelog.unsplash.com:443 (tlsv1 alert internal error). Die Redirect-Kette wurde mit curl -L verfolgt. Die Archivlücke stammt aus der Wayback-CDX-API: letzter 200-Snapshot von changelog.unsplash.com am 24.03.2024, erster von unsplash.com/documentation/changelog am 23.08.2024.

4 Issue-Titel sowie Erstellungs- und Schließdaten wurden aus der GitHub-REST-API gelesen (mui/material-ui#42736, nextcloud/unsplash#115, sindresorhus/Actions#248) sowie aus der drupal.org-JSON-API für gin_login-Issue 3324054, dessen Text im November 2022 „I get always a Heroku application error“ berichtet.

5 Zählungen: GitHub-Codesuch-API (3.344 Dateien; eine Stichprobe von 100 Ergebnissen, dedupliziert auf 77 Repositories, von denen 12 nach dem 11. Juni 2024 erstellt und 20 in den vorangegangenen 12 Monaten mit Pushes versehen worden waren); npm-Registry-Download-API (unsplash-source-es6, 23 Downloads in den vorangegangenen 30 Tagen); Stack-Exchange-/search/excerpts (1.459 Beiträge). Die Codesuche erfasst nur indexierte öffentliche Repositories, jede Zahl ist also eine Untergrenze.

Häufig gestellte Fragen

Ist source.unsplash.com nur down, oder wurde es dauerhaft abgeschaltet?
Dauerhaft. Unsplash kündigte das Sunset am 11. Juni 2024 an — „we will first wind down by disabling the search feature, and in the coming weeks turn off the application entirely“ — nachdem der Dienst bereits am 25. November 2021 als deprecated markiert worden war. Jedes Pattern (/random, /1600x900/?query, /collection/…, /daily) liefert HTTP 503 mit Herokus generischer Application Error-Seite. Der Hostname wird weiterhin aufgelöst, weshalb der Fehler als kaputtes Bild statt als Netzwerkfehler in Erscheinung tritt.
Was ist der direkte Ersatz für source.unsplash.com/random?
Es gibt keinen schlüssellosen Drop-in-Ersatz, und das sollte man früh akzeptieren. Drei Ersatzlösungen existieren. Eine feste CDN-URL — images.unsplash.com/photo-…?w=1600&h=900&fit=crop — benötigt keinen Key, liefert aber immer dasselbe Foto, was für die meisten dekorativen Zwecke ohnehin ausreichte. Die offizielle API, GET https://api.unsplash.com/photos/random mit einem Authorization: Client-ID-Header, stellt die Zufälligkeit wieder her, muss aber serverseitig aufgerufen werden. Ein eigener kleiner Proxy vor diesem Endpoint ist die einzige Option, die eine schlüssellose URL zurückgibt, die man direkt in ein <img>-Tag einsetzen kann.
Warum generieren KI-Coding-Tools 2026 immer noch source.unsplash.com-URLs?
Weil die URL rund acht Jahre lang dokumentiert, gelehrt und kopiert wurde, und ein Trainingskorpus nicht abläuft, wenn ein Dienst abgeschaltet wird. Gemessen am 30. August 2026: Die GitHub-Codesuche liefert immer noch 3.344 Dateien, die die URL enthalten, und in einer Stichprobe von 100 Dateien wurden 12 von 77 Repositories nach der Abschaltung erstellt. Auch von Menschen geschriebene Prompt-Bibliotheken wiederholen die Anweisung — ein weitverbreiteter GPT-Prompt sagt dem Modell immer noch, es solle „use unsplash API( https://source.unsplash.com/1280x720/?… )“ verwenden. Behandle jede von einem Modell geschriebene Bild-URL als ungeprüft und kontrolliere Statuscodes in der CI.
Kann ich ohne API-Key noch ein zufälliges Unsplash-Foto bekommen?
Nicht direkt von Unsplash — die Zufallsauswahl liegt jetzt hinter /photos/random, was eine Client-ID erfordert. Zwei schlüssellose Wege bleiben: ein selbst gehosteter Proxy, bei dem der Key serverseitig bleibt und die öffentliche URL wie die alte aussieht, oder ein Drittanbieter-Platzhalterdienst wie Lorem Picsum (picsum.photos/800/600), der echte Fotografien ohne Key liefert, aber ganz ohne Motiv-Targeting.
Erlaubt die Unsplash-API das Herunterladen und Selbst-Hosten der Bilder?
Nein. Anders als die meisten APIs verlangt Unsplash Hotlinking: Die von der API zurückgegebenen Bild-URLs müssen direkt eingebettet werden, damit Foto-Views dem Fotografen zugerechnet werden. Drei Pflichten kommen damit einher — behalte den ixid-Parameter bei, wenn du die URL skalierst oder zuschneidest, nenne Fotograf und Unsplash als Quelle, und rufe den Download-Endpoint des Fotos auf, wenn ein Nutzer die Datei herunterlädt. Die Dateien auf ein eigenes CDN zu spiegeln, ist die eine Optimierung, die man sich nicht erlauben darf.
Warum hat die Abkündigung von 2021 bestehende Nutzer nicht geschützt?
Weil Ankündigung und Richtlinie nicht dasselbe abdeckten. Der Changelog-Eintrag vom 25. November 2021 versprach, dass „existing uses will continue to work“, und nannte kein Enddatum. Unsplashs veröffentlichte Deprecation-Policy — mindestens drei Wochen Vorlauf plus ein Warning-Header — gilt für öffentlich dokumentierte Felder und Endpoints, und derselbe Absatz besagt, dass alles Undokumentierte sich ohne Vorwarnung ändern kann. Source war nie ein dokumentierter Endpoint der API und fiel damit aus der Richtlinie heraus, die es hätte schützen können.
Wie finde ich jede tote source.unsplash.com-URL in meinem Projekt?
Drei Durchgänge, zehn Minuten. Durchsuche das Repository per Grep, inklusive Docs, Tests, Fixtures und READMEs — grep -rn "source.unsplash.com" . — da diese URLs in Beispielcode am längsten überleben. Frag die Datenbank ab, denn in CMS-Artikeltexten verstecken sie sich (WHERE body LIKE '%source.unsplash.com%'). Dann crawle deinen gebauten Output: Extrahiere jede Bild-URL, rufe sie einzeln auf und liste alles auf, was nicht 200 liefert. Füge diesen letzten Schritt der CI hinzu, dann lässt ein totes Drittanbieter-Asset den Build fehlschlagen statt eine Seite kaputtzumachen.

Schluss mit der Jagd nach Schlüsselwörtern. Beschreiben Sie, was Sie meinen.

Durchsuchen Sie 9M+ kostenlos nutzbare Bilder nach Bedeutung — in jeder Sprache, in unter 100 ms.