source.unsplash.com zniknęło: sekcja zwłok i wszystkie sposoby na zastąpienie
Wycofane w 2021 roku z zapewnieniem „istniejące zastosowania będą nadal działać”, wyłączone w czerwcu 2024, a mimo to wciąż wpisywane w nowy kod. Wyważona sekcja zwłok — oraz trzy zamienniki, w tym proxy przywracające losowość bez klucza API.
Serwis ze zdjęciami stockowymi wyłączył subdomenę, a dwa lata później wciąż psuje strony dokumentacji, ekrany logowania, ćwiczenia kursowe i świeżo wygenerowany kod. To sekcja zwłok pewnego adresu URL — co robił, co go zabiło i co postawić na jego miejsce — a także wyważone spojrzenie na dziwniejszą część tej historii: maszyny piszące za nas kod nie zauważyły, że go nie ma.
Odpowiedzi HTTP, oba wpisy z changeloga zacytowane słowo w słowo, limity API, systemy śledzenia zgłoszeń projektów, które się zepsuły, oraz liczby z GitHub, npm i Stack Overflow — wszystko to pochodzi ze źródeł pierwotnych, a metodologię dla każdego z nich opisano w przypisach. Jeśli interesuje Cię tylko rozwiązanie, przejdź od razu do tabeli migracji.
Co dziś dostajesz, jeśli wciąż o to pytasz
Jedno polecenie, bez klucza, powtarzalne na dowolnej maszynie:
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
# treść: iframe wskazujący na herokucdn.com/error-pages/application-error.html
Nic tu nie jest błędem DNS. source.unsplash.com nadal się rozwiązuje — to CNAME do hosta
herokudns.com — więc żądanie otrzymuje odpowiedź, tyle że nie od aplikacji. Ten
szczegół ma większe znaczenie, niż mogłoby się wydawać: przeglądarka, która szybko dostaje
503 z treścią HTML, renderuje symbol zastępczy uszkodzonego obrazu, a każdy kod
odczytujący response.ok albo obsługę zdarzenia onerror, której nigdy nie
napisałeś, trafia na ścieżkę błędu, której nigdy nie przetestowałeś.
| Wzorzec URL | Co kiedyś zwracał | Dziś |
|---|---|---|
source.unsplash.com/random | Losowe zdjęcie, dowolny rozmiar | 503 |
source.unsplash.com/random/1600x900 | Losowe zdjęcie, przycięte do rozmiaru | 503 |
source.unsplash.com/1600x900/?apple,desk | Losowe zdjęcie pasujące do fraz wyszukiwania | 503 |
source.unsplash.com/featured/1600x900?nature | Losowe zdjęcie wyróżnione | 503 |
source.unsplash.com/collection/190727/800x600 | Losowe zdjęcie z kolekcji | 503 |
source.unsplash.com/user/scottwebb/1600x900 | Losowe zdjęcie jednego fotografa | 503 |
source.unsplash.com/daily | Zdjęcie dnia | 503 |
Sprawdzone indywidualnie przy pomocy curl -o /dev/null -w "%{http_code}". Funkcja
wyszukiwania została wygaszona jako pierwsza, zgodnie z zapowiedzią; dziś cała aplikacja jest
wyłączona, więc to rozróżnienie już nie istnieje.
Trzy lata między „wycofywane” a „wyłączone”
Oba ogłoszenia wciąż da się odczytać, w jednym miejscu, pod adresem unsplash.com/documentation/changelog. Cytowane w całości, bo brzmienie to cała historia:
25 listopada 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 czerwca 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.”
Odczytane po kolei, mechanizm awarii staje się oczywisty. Notatka z 2021 roku zawierała obietnicę (existing uses will continue to work) i żadnej daty. Deweloper, który przeczytał ją w 2021 roku, miał wszelkie powody, by zostawić działający kod w spokoju; deweloper, który dołączył do projektu w 2022 roku, w ogóle jej nie przeczytał. Notatka z 2024 roku dała „nadchodzące tygodnie”, trzy lata później, na stronie, której nikt nie dodał do zakładek.
Unsplash publikuje politykę wycofywania funkcji i jest ona rozsądna — dokumentacja stwierdza,
że dla publicznie udokumentowanych pól i punktów końcowych zmiany są ogłaszane w changelogu z
wyprzedzeniem co najmniej 3 tygodni, a punkty końcowe w okresie wycofywania
zwracają nagłówek Warning. Ten sam akapit zawiera zdanie, które wyjaśnia, dlaczego
nic z tego nie chroniło Source: „For any non-publicly documented fields or endpoints, we may
make changes to these with no warning”. Source nigdy nie był punktem końcowym udokumentowanego
API. Znajdował się poza polityką, która mogłaby go objąć.
- Praktyczna lekcja nie brzmi „Unsplash był niedbały”. Brzmi ona: adres URL, którego można użyć bez czytania jakiejkolwiek dokumentacji, to adres URL, którego polityki wycofywania też nie przeczytałeś.
- Awarie poprzedzały ogłoszenie. Zgłoszenie w Drupalu z dnia 28 listopada 2022 już wtedy raportowało „I get always a Heroku application error”, osiemnaście miesięcy przed wpisem o wygaszeniu. Tak właśnie umierają takie usługi: powoli, a potem w ogłoszeniu, którego nigdy nie widzisz.
Ogłoszenie trudniej znaleźć niż samą awarię
Wycofanie z 2021 roku opublikowano na changelog.unsplash.com i to właśnie do tego
adresu URL prowadzą wszystkie ówczesne zgłoszenia błędów — w tym wspomniane wyżej zgłoszenie z
Drupala. Trzy pomiary:
- Punkt końcowy HTTPS jest uszkodzony.
openssl s_client -connect changelog.unsplash.com:443zwracatlsv1 alert internal error— negocjacja kończy się niepowodzeniem, zanim zostanie przedstawiony jakikolwiek certyfikat. Każdy link z ery 2021, który byłhttps://, jest więc martwy w przeglądarce. - Przez zwykłe HTTP następuje przekierowanie, ale bezużyteczne. Podążenie za
http://changelog.unsplash.com/deprecations/2021/11/25/source-deprecation.htmlkończy się, dwa przeskoki później, błędem400pod adresemunsplash.com/@documentation/changelog/deprecations/2021/11/25/source-deprecation/html— ścieżka została pochłonięta przez trasę nazw użytkowników serwisu. - Archiwum ma dziurę dokładnie tam, gdzie doszło do wygaszenia. Ostatnia udana migawka starego changeloga w Wayback Machine pochodzi z 24 marca 2024; pierwsza migawka nowego — z 23 sierpnia 2024. Wygaszenie ogłoszono 11 czerwca 2024 — w środku tej pięciomiesięcznej luki.
Nic z tego nie jest spiskiem; to zwyczajna migracja CMS. Ale konsekwencja jest realna i to właśnie dlatego ten artykuł cytuje oba wpisy w całości: pierwotny zapis wycofania powinien przetrwać dłużej niż to, co wycofuje, a tutaj niewiele brakowało, by tak się nie stało.
Co faktycznie się zepsuło
Nie chodzi o projekty poboczne. Poniższe awarie to publiczne wpisy w systemach śledzenia zgłoszeń; tytuły, daty i statusy pochodzą z API GitHub i drupal.org.
| Projekt | Zgłoszenie | Otwarte | Co mówi |
|---|---|---|---|
| MUI (Material UI) | #42736 | 24 cze 2024 | „[docs] Random Unsplash photo URL is no longer functional” — oficjalny szablon Sign-in side dostarczał martwy obraz. Zamknięte trzy dni później. |
| Nextcloud | #115 | 17 sty 2023 | „Migrate to Unsplash API” — aplikacja tła była zbudowana na URI Source. Otwarte przez osiemnaście miesięcy, zamknięte 16 lipca 2024. |
| sindresorhus/Actions | #248 | 28 maj 2024 | „Get Unsplash Image: 503 Error” — akcja Shortcuts na iOS/macOS, uszkodzona dwa tygodnie przed ogłoszeniem wygaszenia. |
| Drupal — Gin Login | #3324054 | 28 lis 2022 | „Unsplash has deprecated source.unsplash.com — this delays reCAPTCHA from loading, preventing users from logging in.” |
Przeczytaj ostatni wiersz jeszcze raz, bo to ten, który warto zapamiętać. Obraz dekoracyjny obok formularza logowania — najbardziej oczywisty, niekrytyczny element na stronie — przerodził się w awarię uwierzytelniania, ponieważ powolne żądanie do zewnętrznego serwisu blokowało CAPTCHA, której potrzebował formularz logowania. Nikt tego tak nie zaprojektował. Wynikło to z kolejności, w jakiej przeglądarka ładuje elementy.
Twój asystent kodowania nie dostał notatki
Oto część, która zamienia awarię z 2024 roku w problem roku 2026.
source.unsplash.com był dokumentowany, opisywany na blogach, nauczany i kopiowany
przez mniej więcej osiem lat. Cały ten tekst znajduje się w danych treningowych modeli, które
dziś piszą za nas kod startowy — a tekst się nie przeterminowuje. Trzy liczby:
| Pomiar | Wartość na dzień 30 sie 2026 | Sposób pomiaru |
|---|---|---|
Pliki zawierające source.unsplash.com |
3344 | API wyszukiwania kodu GitHub, q=source.unsplash.com (tylko zindeksowany kod publiczny — to dolna granica, nie suma całkowita) |
| Repozytoria w próbce 100 plików utworzone po wygaszeniu | 12 z 77 | To samo zapytanie, 100 wyników, zdeduplikowane do 77 repozytoriów, created_at porównane do 11 czerwca 2024 |
| …oraz repozytoria w tej próbce, do których wprowadzono zmiany w ciągu ostatnich 12 miesięcy | 20 z 77 | Żywe repozytoria, nie archiwa — w tym elastic/kibana, którego plik demo wciąż zawiera imageUrl: 'https://source.unsplash.com/64x64/?dingo' |
Miesięczne pobrania unsplash-source-es6 |
23 | API rejestru npm — wrapper do martwej usługi, ostatnio publikowany w 2022 roku, wciąż instalowany |
| Posty na Stack Overflow wspominające tę usługę | 1459 | API Stack Exchange, suma z /search/excerpts |
Najbardziej bezpośredni dowód nie znajduje się wcale w kodzie aplikacji — znajduje się w promptach. Najwyżej sklasyfikowany wynik dla tego wyszukiwania to biblioteka promptów systemowych GPT zawierająca linijkę „please use unsplash API( https://source.unsplash.com/1280x720/?<PUT YOUR QUERY HERE>”. Ta instrukcja wciąż jest kopiowana do nowych asystentów. Model nie weryfikuje adresu URL; kazano mu go użyć, a każdy przykład, jaki kiedykolwiek widział, był z tym zgodny.
Awaria w generowanym kodzie ma więc dwie niezależne przyczyny, a naprawienie jednej nie naprawia drugiej: nieaktualne dane treningowe oraz nieaktualne instrukcje napisane przez ludzi na ich podstawie. Tak czy inaczej, objaw jest ten sam — cała rodzina obrazów, które nigdy się nie ładują:
source.unsplash.com/random/1200x800 # 503 od połowy 2024 — nigdy nie wróci
images.unsplash.com/photo-… # prawdziwy CDN, ale zapamiętane ID mogą nie istnieć
via.placeholder.com/400 # szary prostokąt, trafiony na produkcję
placehold.co/800x600 # szary prostokąt, celowo
picsum.photos/800/600 # prawdziwe zdjęcie, niezwiązane z Twoją stroną
/placeholder.png # plik, którego nigdy nie dodano do repozytorium
Przypis do drugiej linijki tej listy: podczas pisania tego artykułu via.placeholder.com
również nie kończył negocjacji TLS z naszej sieci testowej i odpowiadał 403 przez
zwykłe HTTP. Sprawdź to z własnej sieci, zanim mu zaufasz — mechanizm zapasowy, po który sięgają
te narzędzia, może mieć własną historię awarii.
Tylko pierwszy przypadek jest zepsuty. Pozostałe są gorsze w subtelniejszy sposób: ładują się, układ wygląda na ukończony, a nikt nie zauważa, że strona jest zilustrowana niczym konkretnym. I nic z tego nie dotyczy wyłącznie obrazów — to ogólny kształt problemu. Obraz internetu w głowie modelu to migawka, a punkty końcowe, flagi CLI, nazwy pakietów i darmowe plany wciąż się zmieniają po zamknięciu migawki.
Tabela migracji
Istnieją dokładnie trzy kierunki, a uczciwy sposób ich przedstawienia to pokazanie, z czego rezygnujesz. Wybierz najpierw kolumnę, a potem przeczytaj swój wiersz.
| Stary adres URL Source | A. Stały adres URL CDNbez klucza · bez losowości | B. Unsplash APIklucz · wywołanie po stronie serwera | C. Własny proxyklucz ukryty · losowość z powrotem |
|---|---|---|---|
/random |
images.unsplash.com/photo-… — jedno wybrane przez Ciebie zdjęcie |
GET /photos/random |
/?w=1600 |
/random/1600x900 |
…?w=1600&h=900&fit=crop |
/photos/random + parametry Imgix na zwróconym adresie URL |
/?w=1600&h=900&fit=crop |
/1600x900/?apple,desk |
Brak odpowiednika — wybierz zdjęcie ręcznie | /photos/random?query=apple,desk |
/?query=apple,desk&w=1600 |
/featured/1600x900?nature |
Brak odpowiednika | /photos/random?query=nature „featured” nie ma następcy |
/?query=nature&w=1600 |
/collection/67920491/1600x900 |
Brak odpowiednika | /photos/random?collections=67920491 |
/?collections=67920491&w=1600 |
/user/scottwebb/1600x900 |
Brak odpowiednika | /photos/random?username=scottwebb |
/?username=scottwebb&w=1600 |
/daily |
Przypnij jedno zdjęcie, rotuj je przy każdym buildzie | Brak odpowiednika — samodzielnie cache'uj jedno losowe zdjęcie przez 24 h | To samo, z pamięcią podręczną w proxy |
Opcja A jest tą, której faktycznie chce większość ludzi. Jeśli obraz był dekoracyjny — hero, panel boczny logowania, tło karty — nigdy nie potrzebowałeś innego zdjęcia przy każdym żądaniu. Wybierz jedno, zachowaj adres URL CDN, a strona przestanie zależeć od czegokolwiek losowego:
<img src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1600&h=900&fit=crop&auto=format"
width="1600" height="900" alt="…">
# Oficjalnie obsługiwane parametry: w, h, crop, fit, fm, auto=format, q, dpr.
# Zachowaj parametr ixid nadany przez API — to on raportuje wyświetlenie.
Opcja B to ścieżka oficjalna i przenosi wywołanie na stronę serwera, ponieważ
Client-ID we front-endowym JavaScripcie to opublikowane poświadczenie. Zwróć uwagę na
dwie reguły, na których ludzie się potykają: collections/topics nie
można łączyć z query w tym samym żądaniu, a count (maks. 30) zmienia
kształt odpowiedzi na tablicę, nawet gdy wynosi 1.
curl "https://api.unsplash.com/photos/random?query=nature&orientation=landscape" \
-H "Authorization: Client-ID YOUR_ACCESS_KEY" \
-H "Accept-Version: v1"
# → JSON. Obraz znajduje się pod .urls.regular / .urls.raw (w/h/fit dodaj sam).
# → X-Ratelimit-Limit: 1000 X-Ratelimit-Remaining: 999
Opcja C: odtwórz Source w około czterdziestu liniach
Jeśli to, co straciłeś, to naprawdę zachowanie — bezkluczowy adres URL, który za każdym razem
zwraca inne zdjęcie, użyteczny wprost ze znacznika <img>, w polu CMS-a albo na
stronie statycznej, gdzie nie ma serwera — musisz uruchomić ten punkt końcowy samodzielnie. To
jeden niewielki worker przed API, a trzy rzeczy, które sprawiają, że przetrwa on kontakt z
produkcją, to pamięć podręczna, sprawdzanie nagłówka referer i przekazywanie reszty ciągu
zapytania do CDN.
// Cloudflare Workers. Gdzie indziej (Deno Deploy, Val Town…) kształt jest ten sam,
// ale otwórz nazwaną pamięć podręczną przez caches.open() zamiast caches.default.
// UNSPLASH_KEY pozostaje po stronie serwera. Wywołujący nigdy go nie widzą.
const ALLOWED = ["example.com", "www.example.com"]; // tylko Twoje domeny
const API_PARAMS = ["query", "collections", "topics", "username", "orientation"];
const TTL = 60; // sekundy — chroni godzinowy limit
const host = (value) => { try { return new URL(value).hostname; } catch { return null; } };
export default {
async fetch(req, env, ctx) {
// 0. Tylko GET: Cache API odmawia zapisania czegokolwiek innego, a punkt
// końcowy obrazów nie ma innego czasownika, na który mógłby odpowiadać.
if (req.method !== "GET")
return new Response("Method not allowed", { status: 405 });
const url = new URL(req.url);
// 1. Tylko Twoje własne strony mogą go osadzać — publiczny punkt końcowy
// losowych zdjęć w otwartym internecie to cudzy limit żądań do spalenia.
const ref = req.headers.get("referer"); // brak u wielu legalnych klientów
if (ref && !ALLOWED.includes(host(ref)))
return new Response("Forbidden", { status: 403 });
// 2. Cache dla każdej kombinacji parametrów, dzięki czemu strona z 12
// obrazami kosztuje jedno wywołanie API na minutę, nie dwanaście na render.
const cache = caches.default;
const hit = await cache.match(req);
if (hit) return hit;
// 3. Zapytaj oficjalne API o losowe zdjęcie.
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 tutaj zwykle oznacza godzinowy limit, nie zły klucz — podnieś TTL, nie panikuj.
if (!r.ok) return new Response("Upstream " + r.status, { status: 502 });
const photo = await r.json();
// 4. Odbuduj adres URL obrazu: zachowaj ixid, dołącz parametry rozmiaru od wywołującego.
const img = new URL(photo.urls.raw); // .raw już niesie ixid
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,
// Podpis autora podróżuje razem z przekierowaniem; wartości nagłówków muszą być ASCII, stąd kodowanie.
"X-Photo-Credit": encodeURIComponent(photo.user.name + " on Unsplash"),
"X-Photo-Link": photo.links.html,
}});
ctx.waitUntil(cache.put(req, res.clone()));
return res;
},
};
Migracja adresu URL sprowadza się wtedy do zwykłego „znajdź i zamień”, co jest właśnie tym, co czyni tę opcję wartą tych dwudziestu minut:
- https://source.unsplash.com/collection/67920491/1600x900
+ https://img.example.com/?collections=67920491&w=1600&h=900&fit=crop
Dwie uwagi projektowe, obie kosztowały kogoś nieprzyjemne popołudnie, zanim zostały spisane.
Przekierowanie (302) zamiast proxy'owania bajtów zdejmuje z Ciebie problem
przepustowości i pozwala liczyć wyświetlenie w CDN Unsplash, o co proszą wytyczne. A
kontrola nagłówka Referer jest celowo pobłażliwa, gdy nagłówek jest nieobecny —
wielu legalnych klientów go usuwa — jednocześnie wciąż powstrzymując oczywisty przypadek, w
którym Twój punkt końcowy staje się czyimś darmowym API obrazów.
Zasady, które dziedziczysz w chwili użycia API
Source nie miał zasad, bo nie miał konta. API ma pięć, które zmieniają sposób projektowania rozwiązania — wszystkie z aktualnej dokumentacji:
- Limity żądań są godzinowe i na początku niewielkie. 50 żądań/godzinę
w trybie demo; 1000/godzinę po zatwierdzeniu aplikacji do produkcji. Liczą się
tylko wywołania do
api.unsplash.com— żądania obrazów doimages.unsplash.comsię nie liczą. OdczytujX-Ratelimit-Remainingprzy każdej odpowiedzi. - Hotlinkowanie jest obowiązkowe, nie tylko dozwolone. Unsplash wymaga, by adresy URL obrazów zwracane przez API były osadzane bezpośrednio, dzięki czemu wyświetlenia zdjęcia można przypisać fotografowi. Kopiowanie pliku na własny CDN to optymalizacja, na którą nie masz swobody.
- Zachowaj parametr
ixid. Zmiana rozmiaru i przycinanie zwróconego adresu URL jest oczekiwane; usuwanie parametru identyfikującego Twoją aplikację — nie. - Podpis autorski i śledzenie pobrań są częścią umowy — fotograf i Unsplash otrzymują podpis, a „pobranie” jest raportowane przez punkt końcowy pobierania zdjęcia, gdy użytkownik zapisuje plik — to zdarzenie musisz sam wywołać.
- Produkty rozproszone wymagają dynamicznej rejestracji klienta. Jeśli dostarczasz wtyczkę, motyw albo samodzielnie hostowany CMS, jeden współdzielony klucz jest jednocześnie naruszeniem polityki i pojedynczym punktem awarii; API ma dokładnie dla tego przypadku dedykowany przepływ rejestracji.
To dobry moment, by uczciwie ograniczyć zakres: skoro i tak podłączasz API i klucz, wybór którego API obrazów nagle staje się otwarty i warto poświęcić na to pięć minut, zanim napiszesz klienta. Porównaliśmy darmowe opcje — limity, zasady, zachowanie wyszukiwania i kształt odpowiedzi — w porównaniu darmowych API zdjęć stockowych.
Jeśli chciałeś tylko symbolu zastępczego, powiedz to wprost
Duża część użycia Source nigdy tak naprawdę nie dotyczyła Unsplash. Chodziło o „wstaw coś w kształcie obrazu, dopóki buduję układ”. Do tego wciąż istnieją usługi bezkluczowe i to one są właściwą odpowiedzią:
| Usługa | Klucz? | Co dostajesz | Gdzie kończą się jej możliwości |
|---|---|---|---|
| Lorem Picsum | Nie | Prawdziwe fotografie: picsum.photos/800/600, stabilne przez /id/237/… albo /seed/xxx/…, plus ?grayscale i ?blur=1..10. Punkt końcowy /v2/list podaje podpis strony Unsplash i autora dla każdego zdjęcia. |
Zupełny brak targetowania tematu. Zdjęcie nie będzie miało związku z Twoją stroną. |
| placehold.co | Nie | Podpisane prostokąty w dowolnym rozmiarze — uczciwe wypełnienie makiety. | To szary prostokąt i tak też wygląda na zrzucie ekranu wysłanym klientowi. |
| Openverse | Nie | Katalog na otwartych licencjach z publicznym API, prowadzony przez WordPress.org. | Dopasowanie słów kluczowych, a licencje różnią się w zależności od pozycji — musisz je czytać. |
Rozróżnienie, które ma znaczenie: symbol zastępczy z definicji jest tymczasowy. Jeśli obraz przetrwa do produkcji, przestaje być symbolem zastępczym — staje się ilustracją, której nikt nie wybrał, a czytelnik to zauważy.
Jeden klucz zamiast trzech
Oto część migracji, której nikt nie planuje: osoby odchodzące od Source rzadko lądują na
jednym API. Strona potrzebuje hero, dwóch obrazów sekcji i czegoś do siatki kart, a
uczciwą odpowiedzią jest zwykle Unsplash plus Pexels plus Pixabay — trzy
rejestracje, trzy schematy uwierzytelniania, trzy kształty JSON, trzy modele paginacji i trzy
zestawy zasad przypisania autorstwa, wszystko po to, by wypełnić te same znaczniki
<img>. Ta praca integracyjna to prawdziwy rachunek za zniknięcie bezkluczowego
adresu URL i przychodzi tygodnie po awarii, która go spowodowała.
Zredukowanie tego do jednej integracji jest właśnie tym, po co zbudowaliśmy Pexafy: jeden klucz do 9 bibliotek na darmowej licencji w jednym schemacie, z semantycznym wyszukiwaniem na poziomie zdania — dzięki czemu pełen opis w rodzaju „pęknięty ekran telefonu na drewnianym biurku, ujęcie z góry” zwraca ranking wyników zamiast niczego. Dwa ograniczenia, powiedziane wprost, bo cały ten artykuł dotyczy tego, by nie dać się zaskoczyć drugi raz: to wymaga klucza, więc nie przywraca tego, czym był Source — należy do tej samej kategorii co oficjalne API Unsplash powyżej; a fotografia, którą oferuje, jest na darmowej licencji, nie redakcyjna czy markowa.
Element, który jest naprawdę nowy, jest wymierzony w asystentów opisanych
powyżej: serwer MCP pod adresem mcp.pexafy.com/mcp oznacza, że model, który
inaczej wyrecytowałby z pamięci adres URL obrazu, może przeszukać prawdziwy katalog i zwrócić
zdjęcie, które istnieje, z dołączonym podpisem autorskim. To lepsza odpowiedź na martwe adresy
URL pisane przez maszyny niż jakakolwiek reguła lintera, a uzasadnienie opisujemy w
infrastrukturze
wyszukiwania obrazów dla agentów AI.
Zaudytuj swój zbiór zasobów w dziesięć minut
Bez względu na to, na co migrujesz, zrób najpierw to — nie da się naprawić adresów URL, których nie znalazłeś. Source jest tylko dzisiejszym przykładem; te same trzy kroki dotyczą każdego zewnętrznego zasobu, który osadzasz.
# 1. Wszystko w repozytorium, w tym dokumentacja, testy, fixture'y i README.
grep -rn --binary-files=without-match \
-e "source.unsplash.com" -e "via.placeholder.com" -e "/placeholder.png" .
# 2. Wszystko, co trzyma baza danych — treści CMS to miejsce, gdzie to zostaje najdłużej.
psql -c "SELECT id FROM posts WHERE body LIKE '%source.unsplash.com%'"
# 3. Wszystko, o co faktycznie pyta zbudowana strona: przeskanuj ją i wypisz awarie.
# Dopasuj atrybut, nie rozszerzenie pliku — adresy URL obrazów rzadko kończą się na .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 ← tego właśnie szukasz
Potem zdecyduj, raz na zawsze, ile mogą Cię kosztować obrazy zewnętrzne. Cztery zasady, które przetrwają kolejne wyłączenie usługi, bez względu na to, kto je spowoduje:
- Pobieraj obraz w czasie builda, nie w czasie żądania. Obraz rozwiązywany podczas builda zawodzi w CI, na oczach dewelopera, zamiast o 3 nad ranem, na oczach użytkownika.
- Nigdy nie pozwól, by zasób dekoracyjny blokował ścieżkę krytyczną. Nie
wstępnie ładuj niczego zewnętrznego nad formularzem logowania; daj każdemu zewnętrznemu
<img>mechanizm zapasowyonerrororaz jawnewidth/height, tak by awaria kosztowała pusty prostokąt, a nie przesunięcie układu czy zawieszony skrypt. - Dodaj kontrolę do CI. Krok 3 powyżej, uruchomiony na zbudowanym wyniku, zamienia „ktoś w końcu zauważył” w czerwony build. To jedyny krok, który zapobiega powtórce.
- Budżetuj zależności zewnętrzne tak jak każde inne. Zapisz, od jakich hostów Twoje strony mogą zależeć i co się dzieje, gdy każdy z nich pada. Adres URL, do którego nie musiałeś się rejestrować, wciąż jest zależnością — Source udowodnił, że to po prostu zależność, do której nikt się nie przyznaje.
Źródła i przypisy
1 Każdy kod statusu, każda liczba i każdy cytat w tym artykule
pochodzi z pierwotnego źródła, sprawdzonego dnia 30 sierpnia 2026.
Kody statusu HTTP pobrano za pomocą curl dla każdego wzorca URL; wszystkie zwracały
503 z server: Heroku i treścią osadzającą
herokucdn.com/error-pages/application-error.html. Rozwiązywanie DNS potwierdzono
tego samego dnia (CNAME do hosta herokudns.com).
2 Oba wpisy z changeloga cytowane są dosłownie z
unsplash.com/documentation/changelog. Brzmienie polityki wycofywania (3 tygodnie
wyprzedzenia, nagłówek Warning oraz wyjątek dla punktów końcowych niedokumentowanych
publicznie) pochodzi z unsplash.com/documentation, tego samego dnia.
3 Awarię TLS odtworzono za pomocą
openssl s_client -connect changelog.unsplash.com:443 (tlsv1 alert internal
error). Łańcuch przekierowań prześledzono za pomocą curl -L. Lukę w archiwum
pobrano z API CDX Wayback: ostatnia migawka 200 dla
changelog.unsplash.com z dnia 20240324, pierwsza migawka dla
unsplash.com/documentation/changelog z dnia 20240823.
4 Tytuły zgłoszeń oraz daty utworzenia i zamknięcia odczytano z API
REST GitHub (mui/material-ui#42736, nextcloud/unsplash#115,
sindresorhus/Actions#248) oraz z API JSON drupal.org dla zgłoszenia
gin_login nr 3324054, którego treść raportuje „I get always a Heroku application
error” w listopadzie 2022 roku.
5 Liczby: API wyszukiwania kodu GitHub
(3344 pliki; próbka 100 wyników zdeduplikowana do 77 repozytoriów, z których 12
powstało po 11 czerwca 2024, a 20 miało zmiany wprowadzone w ciągu poprzednich 12
miesięcy); API pobrań rejestru npm (unsplash-source-es6, 23 pobrania w ciągu
poprzednich 30 dni); Stack Exchange /search/excerpts (1459 postów).
Wyszukiwanie kodu obejmuje wyłącznie zindeksowane repozytoria publiczne, więc każda liczba jest
dolną granicą.
Źródła pierwotne: Changelog API Unsplash · Dokumentacja API Unsplash · Wytyczne Unsplash dot. przypisania autorstwa · Status Unsplash · MUI #42736 · Nextcloud #115 · sindresorhus/Actions #248 · Drupal Gin Login #3324054 · Lorem Picsum · Openverse · Dokumentacja API i MCP Pexafy.
Najczęściej zadawane pytania
Czy source.unsplash.com nie działa chwilowo, czy zostało wyłączone na stałe?
/random, /1600x900/?query, /collection/…, /daily) zwraca teraz HTTP 503 z generyczną stroną Application Error od Heroku. Nazwa hosta wciąż się rozwiązuje, więc błąd objawia się jako uszkodzony obraz, a nie błąd sieci.Co jest bezpośrednim zamiennikiem dla source.unsplash.com/random?
images.unsplash.com/photo-…?w=1600&h=900&fit=crop — nie wymaga klucza, ale zawsze zwraca to samo zdjęcie, co w praktyce wystarczało do większości zastosowań dekoracyjnych. Oficjalne API, GET https://api.unsplash.com/photos/random z nagłówkiem Authorization: Client-ID, przywraca losowość, ale musi być wywoływane po stronie serwera. Własne proxy postawione przed tym endpointem to jedyna opcja, która oddaje z powrotem URL bez klucza, gotowy do wstawienia bezpośrednio w tag <img>.Dlaczego narzędzia AI do kodowania wciąż generują adresy source.unsplash.com w 2026 roku?
Czy nadal mogę pobrać losowe zdjęcie z Unsplash bez klucza API?
/photos/random, który wymaga Client-ID. Masz dwie drogi bez klucza: własne proxy, w którym klucz pozostaje po stronie serwera, a publiczny URL wygląda jak stary, albo usługa placeholderów firm trzecich, taka jak Lorem Picsum (picsum.photos/800/600), która serwuje prawdziwe fotografie bez klucza, ale też bez żadnego kierowania na temat.Czy API Unsplash pozwala pobierać i hostować zdjęcia samodzielnie?
ixid przy zmianie rozmiaru lub kadrowaniu URL-a, podanie autora zdjęcia i Unsplash oraz wywołanie endpointu pobierania zdjęcia, gdy użytkownik pobiera plik. Mirroring plików na własnym CDN to jedyna optymalizacja, której nie wolno ci zastosować.Dlaczego zawiadomienie o wycofaniu z 2021 roku nie chroniło dotychczasowych użytkowników?
Warning — dotyczy pól i endpointów publicznie udokumentowanych, a ten sam akapit stwierdza, że wszystko, co nieudokumentowane, może się zmienić bez ostrzeżenia. Source nigdy nie było udokumentowanym endpointem API, więc znalazło się poza polityką, która mogłaby je chronić.Jak znaleźć wszystkie martwe adresy source.unsplash.com w moim projekcie?
grep -rn "source.unsplash.com" . — ponieważ te adresy najdłużej przetrwają właśnie w przykładowym kodzie. Odpytaj bazę danych, bo to w treściach artykułów CMS-a najczęściej się ukrywają (WHERE body LIKE '%source.unsplash.com%'). Następnie przeskanuj zbudowany output: wyodrębnij każdy adres URL obrazu i wyślij do niego zapytanie, listując wszystko, co nie zwraca 200. Dodaj to ostatnie przejście do CI, a martwy zasób zewnętrzny będzie blokował build, zamiast psuć stronę produkcyjną.