Jina Reader — zamiana dowolnego URL-a na treść przyjazną modelom LLM
Doklejasz przed adresem strony prefiks https://r.jina.ai/ i dostajesz czysty markdown zamiast HTML-a z banerami cookies. Reader radzi sobie też z PDF-ami, dokumentami Office i obrazami, ma kilkadziesiąt nagłówków sterujących ekstrakcją i da się go postawić u siebie. Opisujemy API, wpięcie w Laravela, rozliczenie tokenów, self-hosting — oraz dwie rzeczy, o których trzeba wiedzieć przed wdrożeniem: otwarte zgłoszenie SSRF i licencję modeli, która nie jest open source.
Każdy, kto budował cokolwiek opartego o treść ze stron internetowych — wyszukiwanie RAG, agenta przeglądającego dokumentację, monitoring publikacji konkurencji, streszczanie artykułów — zna ten etap. Pobrać stronę, wyrzucić z niej baner zgód, menu, stopkę, pasek newslettera i trzy warstwy skryptów, zostawić sam tekst i podać go modelowi. Brzmi jak drobiazg na godzinę, a potrafi zjeść tydzień: co druga strona renderuje treść dopiero po wykonaniu JavaScriptu, co trzecia serwuje inny HTML botom niż przeglądarce, a reszta zwraca PDF-a.
Jina Reader rozwiązuje dokładnie ten fragment problemu i robi to w sposób, który da się zapamiętać w pięć sekund: przed adresem strony doklejasz https://r.jina.ai/ i w odpowiedzi dostajesz markdown. Bez rejestracji, bez SDK, bez klucza — działa również zwykłym curl-em. Kod jest otwarty (github.com/jina-ai/reader, licencja Apache-2.0) i można go uruchomić na własnym serwerze.
W tym wpisie przechodzimy przez API, sterowanie ekstrakcją, wpięcie w aplikację Laravela, rozliczenie tokenów i uruchomienie u siebie. Na końcu dwie rzeczy, których w materiałach marketingowych nie ma, a które przesądzają o tym, jak wolno tego używać: otwarte zgłoszenie SSRF w wersji self-hosted i licencja modeli, która nie jest licencją open source.
Co Reader właściwie robi
Reader wystawia dwa punkty wejścia:
r.jina.ai/<URL>— pobiera wskazany zasób i zwraca go jako markdown (albo HTML, tekst, zrzut ekranu — do wyboru),s.jina.ai/<zapytanie>— wykonuje wyszukiwanie w sieci, pobiera treść najlepszych wyników i zwraca ją w tej samej postaci, w jednym żądaniu.
Obsługiwane typy zawartości to nie tylko strony HTML:
- strony internetowe — renderowane w headless Chrome przez
puppeteer, więc treść doładowywana JavaScriptem jest widoczna, - PDF-y — parsowane przez PDF.js, z możliwością wyrenderowania każdej strony jako obrazu,
- dokumenty MS Office — Word, Excel i PowerPoint przechodzą przez LibreOffice do PDF-a i HTML-a, a dalej zwykłą ścieżką,
- obrazy — opisywane przez model wizyjno-językowy. Dokumentacja architektury jest tu uczciwa: to nie jest OCR, tylko generowanie opisu, więc nie licz na wierne przepisanie skanu.
Najprostsze możliwe użycie wygląda tak:
curl https://r.jina.ai/https://en.wikipedia.org/wiki/Artificial_intelligencei to jest całe API w wariancie podstawowym. Zwrócony markdown przeszedł już przez @mozilla/readability, czyli tę samą bibliotekę, która stoi za trybem czytnika w Firefoksie — nawigacja, reklamy i elementy poboczne wypadają, zostaje treść.
Silniki pobierania: browser, curl, auto
Sposób pobrania strony wybiera się nagłówkiem x-engine i warto rozumieć, co się wtedy dzieje, bo różnica w czasie odpowiedzi i w skuteczności jest kilkukrotna.
x-engine: browser— pełny headless Chrome. Najwierniejsze renderowanie, wykonuje JavaScript, najdroższe czasowo,x-engine: curl— lekkie pobranie surowego HTML-a przezcurl-impersonate, bez wykonywania JavaScriptu.curl-impersonatepodszywa się pod odcisk TLS prawdziwej przeglądarki, co ma znaczenie przy stronach odrzucających ruch wyglądający na automat,x-engine: auto— domyślny. Reader sam łączy oba podejścia w zależności od charakteru treści.
Jest jeszcze cf-browser-rendering, oparty o REST API Cloudflare — dokumentacja opisuje go jako wariant testowy i awaryjny, z ostrymi limitami. Do produkcji nie jest przeznaczony.
Analogicznie wygląda konwersja HTML-a na markdown: domyślnie działa @mozilla/readability plus własna implementacja reguł inspirowana biblioteką turndown, a eksperymentalnie ReaderLM v2 — model językowy wytrenowany specjalnie do zamiany HTML-a na markdown. Wersja v3 oparta o model wizyjny, zamieniająca zrzut ekranu wprost na markdown, jest w planach.
Nagłówki: cała konfiguracja bez ani jednego pliku
Reader nie ma pliku konfiguracyjnego po stronie klienta — wszystko ustawia się nagłówkami HTTP pojedynczego żądania. To jest największa zaleta tego API i jednocześnie powód, dla którego warto raz przejść przez listę opcji, zamiast zostawać przy domyślnych.
Format odpowiedzi
x-respond-with: markdown— markdown bez filtrowania przez readability (czyli więcej treści, także tej pobocznej),x-respond-with: html—documentElement.outerHTMLpo wyrenderowaniu,x-respond-with: text—document.body.innerText,x-respond-with: screenshot— adres zrzutu widocznego obszaru,pageshot— całej strony,x-respond-with: frontmatteralbomarkdown+frontmatter— markdown z blokiem YAML na górze.
Osobno działa tryb JSON, włączany zwykłym Accept:
curl -H "Accept: application/json" \
https://r.jina.ai/https://en.m.wikipedia.org/wiki/Main_PageW odpowiedzi dostajesz obiekt z tytułem, opisem, adresem, treścią i — co istotne przy rozliczeniu — liczbą zużytych tokenów. Przy wpinaniu Readera w aplikację to jest wariant, którego chcesz: tytuł strony masz podany osobno, zamiast zgadywać go z pierwszego nagłówka w markdownie.
Wybór fragmentu strony
x-target-selector: <selektor CSS>— wytnij treść z konkretnego elementu i nic więcej,x-wait-for-selector: <selektor CSS>— poczekaj z odpowiedzią, aż element się pojawi,x-detach-invisibles— usuń elementy ukryte (display: none) przed zrzutem treści.
x-target-selector jest w praktyce najczęściej używanym nagłówkiem po tych od formatu. Jeśli pobierasz zawsze ten sam serwis — dokumentację jednego producenta, listę ofert, portal branżowy — jeden celny selektor daje czystszy wynik niż jakakolwiek heurystyka ogólna.
Kiedy uznać stronę za gotową
Aplikacje jednostronicowe potrafią zwrócić pusty <div id="app"></div> i dorysować treść sekundę później. Reader daje na to osobny zestaw opcji:
x-timeout: <sekundy>— maksymalny czas oczekiwania, do 180 sekund,x-respond-timing: html— oddaj surowy HTML natychmiast,x-respond-timing: visible-content— poczekaj, aż tekst będzie czytelny,x-respond-timing: mutation-idle— aż zmiany w drzewie DOM się uspokoją (co najmniej 0,2 s ciszy),x-respond-timing: resource-idle/media-idle/network-idle— kolejno coraz ostrożniej i coraz wolniej, aż do pełnegonetworkidle0.
Osobny przypadek to routing po fragmencie adresu. Wszystko po # nie jest wysyłane na serwer, więc doklejenie takiego URL-a do prefiksu nie zadziała. Rozwiązanie jest opisane w dokumentacji i polega na przesłaniu adresu w ciele żądania:
curl -X POST 'https://r.jina.ai/' -d 'url=https://example.com/#/route'Co zrobić z linkami, obrazami i multimediami
Tu zaczyna się oszczędzanie tokenów, bo w typowym artykule odnośniki potrafią zająć więcej miejsca niż tekst:
x-retain-links: all | none | text | gpt-oss— pełne linki markdown, całkowite usunięcie, sam tekst odnośnika albo cytowania w formacie【{id}†...】z ponumerowaną stopką,x-retain-images: all | none | alt— obrazy w całości, wcale albo sam tekst alternatywny bez adresów,x-retain-media: link | none | text | image | html— analogicznie dla multimediów,x-with-links-summaryix-with-images-summary— doklej na końcu odchudzoną listę odnośników albo obrazów zamiast rozsypywać je po tekście,x-with-generated-alt: true— dogeneruj opisy obrazów, które nie mają atrybutualt, modelem wizyjnym.
Kombinacja x-retain-links: none plus x-retain-images: none potrafi zbić rozmiar odpowiedzi o połowę przy stronach z rozbudowaną nawigacją. Jeśli treść i tak trafia do wektorowej bazy, a nie do człowieka, nie ma powodu płacić za adresy odnośników.
Kontrola długości i dzielenie na fragmenty
x-max-tokens: <liczba>(minimum 500) — przytnij odpowiedź do zadanego budżetu,x-token-budget: <liczba>— odrzuć odpowiedź w całości, jeśli przekracza limit. Różnica jest zasadnicza: pierwsze daje ucięty tekst, drugie mówi „ta strona jest za duża, nie zaczynaj",x-markdown-chunking: truealboh1–h5— podziel treść po nagłówkach,x-markdown-chunking: structuredalbos1–s5— podziel po blokach strukturalnych.
Dzielenie po nagłówkach warto docenić, jeśli budujesz indeks wektorowy. Zamiast pobierać całość i tłuc ją własnym splitterem po liczbie znaków — co regularnie przecina zdanie albo tabelę w połowie — dostajesz fragmenty przycięte tam, gdzie autor tekstu sam postawił granicę.
Gotowe zestawy ustawień
Nagłówek x-preset pakuje typowe kombinacje pod jedną nazwę: reader (do pokazania człowiekowi), index (do indeksowania i embeddingów), research (wynik ustrukturyzowany), agent (codzienne przeglądanie przez agenta) i spider (rekurencyjne obchodzenie serwisu z inwentarzem odnośników). Do pierwszego wdrożenia to sensowny punkt startu — dopiero gdy wynik nie odpowiada, schodzi się do pojedynczych nagłówków.
Pobieranie zza proxy i z ciasteczkami
x-proxy-url— przepuść żądanie przez własne proxy (http,https,socks4,socks5),x-set-cookie— dołóż ciasteczka, na przykład sesyjne. Uwaga: ten nagłówek omija warstwę cache, i słusznie,x-no-cache: true— wymuś świeże pobranie, równoważnex-cache-tolerance: 0,x-cache-tolerance: <sekundy>— określ, jak stara odpowiedź jest jeszcze akceptowalna.
Wyszukiwanie przez s.jina.ai
Drugi endpoint zdejmuje z aplikacji cały etap „znajdź strony, potem je pobierz":
curl https://s.jina.ai/Kiedy%20powstala%20Jina%20AI%3FZwracane są najlepsze wyniki wraz z pobraną i oczyszczoną treścią każdego z nich. Wyszukiwanie da się zawęzić do wskazanych serwisów:
curl 'https://s.jina.ai/Kiedy%20powstala%20Jina%20AI%3F?site=jina.ai&site=github.com'To jest wygodne przy budowaniu agenta, który ma się opierać wyłącznie o dokumentację konkretnego producenta zamiast o cokolwiek, co wyrzuci wyszukiwarka.
Wpięcie w aplikację Laravela
Reader to zwykły HTTP, więc żadna biblioteka nie jest potrzebna — wystarczy fasada Http. Zaczynamy od konfiguracji, i to nie jest szczegół kosmetyczny: trzymanie adresu bazowego w konfiguracji pozwala później przełączyć się z usługi Jiny na własną instancję bez dotykania kodu.
// config/services.php
'jina' => [
'reader_url' => env('JINA_READER_URL', 'https://r.jina.ai'),
'key' => env('JINA_API_KEY'),
],Klasa opakowująca wywołanie, z opcjami nastawionymi na indeksowanie treści:
namespace App\Services;
use Illuminate\Support\Facades\Http;
class ReaderClient
{
public function __construct(private readonly string $baseUrl, private readonly ?string $key) {}
/**
* @return array{title: string, url: string, content: string, usage: array{tokens: int}}
*/
public function fetch(string $url): array
{
return Http::withHeaders(array_filter([
'Authorization' => $this->key ? 'Bearer '.$this->key : null,
'Accept' => 'application/json',
'X-Retain-Links' => 'none',
'X-Retain-Images' => 'none',
'X-Token-Budget' => '20000',
'X-Timeout' => '20',
]))
->timeout(45)
->retry(2, 1000, throw: false)
->get($this->baseUrl.'/'.$url)
->throw()
->json('data');
}
}Kilka decyzji z tego fragmentu warto uzasadnić, bo każda wynika z konkretnej pułapki:
timeout()po stronie klienta większy niżX-Timeout. Reader ma prawo mielić stronę tyle, ile mu pozwolisz nagłówkiem; jeśli klient HTTP rozłączy się wcześniej, zapłacisz za pracę, której wyniku nie zobaczysz,X-Token-BudgetzamiastX-Max-Tokens. Przy indeksowaniu ucięty w połowie dokument jest gorszy niż brak dokumentu — lepiej dostać błąd i obsłużyć go świadomie,retry()zthrow: false, żeby wyjątek poleciał dopiero zthrow()i był jednego typu niezależnie od tego, czy ponowienia się wyczerpały.
Ponieważ każde żądanie kosztuje tokeny, a treść stron zmienia się wolniej niż działa pętla agenta, cache po stronie aplikacji zwraca się natychmiast:
use Illuminate\Support\Facades\Cache;
$document = Cache::remember(
'reader:'.sha1($url),
now()->addDay(),
fn () => $reader->fetch($url),
);Pobieranie kilkudziesięciu adresów naraz jest naturalnym kandydatem na kolejkę — headless Chrome po drugiej stronie nie odpowiada w kilkanaście milisekund, a limit żądań na minutę i tak wymusi rozłożenie tego w czasie. Zadanie na jeden adres, Bus::batch() na całą paczkę i WithoutOverlapping albo RateLimited na wypadek, gdyby ktoś wrzucił do systemu tysiąc URL-i naraz.
Osobno warto zapamiętać jedno: adres, który wkładasz do Readera, musi pochodzić z zaufanego źródła albo przejść walidację. Jeśli użytkownik Twojej aplikacji podaje dowolny URL, a Ty doklejasz go do prefiksu i pobierasz — dokładasz do systemu funkcję „pobierz cokolwiek z sieci w moim imieniu". Przy usłudze Jiny ryzyko bierze na siebie dostawca; przy instancji własnej wraca do Ciebie i wiąże się bezpośrednio z problemem opisanym niżej.
Limity i rozliczenie
Reader działa bez rejestracji, ale przy niskim limicie. Stan na dziś:
r.jina.ai— 20 zapytań na minutę bez klucza, 500 z kluczem (również darmowym), 5000 w wariancie premium,s.jina.ai— bez klucza niedostępny, 100 zapytań na minutę z kluczem, 1000 w wariancie premium.
Rozliczenie jest tokenowe i różni się między endpointami. Dla r.jina.ai liczone są tokeny odpowiedzi — czyli tego, co faktycznie dostajesz, co czyni opisane wyżej nagłówki od przycinania treści realną pozycją w rachunku, a nie kosmetyką. Dla s.jina.ai obowiązuje opłata stała, zaczynająca się od 10 000 tokenów za zapytanie, niezależnie od tego, ile treści wróci.
Nowy klucz dostaje 10 milionów darmowych tokenów, wspólnych dla wszystkich usług Jiny — tego samego klucza używa się do Readera, embeddingów, rerankera, klasyfikatora i segmentera, i z tej samej puli one się rozliczają. Przy testach i niewielkim ruchu ta pula wystarcza na długo.
Jeśli budujesz cokolwiek ponad prototyp, załóż klucz od razu — nie ze względu na tokeny, tylko na limit 20 zapytań na minutę. Przy anonimowym ruchu dochodzi jeszcze mechanizm, który przy nadmiernym obciążeniu jednego adresu czasowo blokuje ten serwis dla użytkowników bez klucza. Prototyp, który dziś działa, jutro potrafi zwrócić błąd bez żadnej zmiany po Twojej stronie.
Uruchomienie u siebie
Gotowy obraz leży w rejestrze GitHuba i startuje jedną komendą:
docker run --rm -p 3000:8081 ghcr.io/jina-ai/reader:ossKontener wystawia dwa porty i warto wiedzieć który do czego: 8080 to HTTP/2 bez szyfrowania (h2c), przeznaczony na produkcję, a 8081 to HTTP/1.1 jako wariant zgodnościowy. Do lokalnych testów wygodniejszy jest 8081, bo rozmawia z nim każde narzędzie; przy wdrożeniu za odwrotnym proxy sensowniej wystawić oba:
docker run --rm -p 3000:8080 -p 3001:8081 ghcr.io/jina-ai/reader:ossDomyślnie instancja jest całkowicie bezstanowa — bez cache, bez limitowania, bez bazy. Dokumentacja architektury nazywa to „Stage 0" i opisuje trzy poziomy:
- Stage 0 — bezstanowy, nic nie jest zapisywane,
- Stage 1 — cache w magazynie zgodnym z S3, nadal bez limitowania,
- Stage 2 — MongoDB indeksujące obiekty w cache plus magazyn S3, z limitowaniem żądań. To jest konfiguracja usługi Jiny i tego poziomu w gałęzi otwartej nie ma.
Włączenie cache to podanie czterech zmiennych — nazwy mają przedrostek GCP_ z powodów historycznych, ale działa każdy magazyn zgodny z S3, łącznie z MinIO:
docker run --rm -p 3000:8081 \
-e GCP_STORAGE_ENDPOINT=https://s3.example.com \
-e GCP_STORAGE_BUCKET=reader-cache \
-e GCP_STORAGE_ACCESS_KEY=... \
-e GCP_STORAGE_SECRET_KEY=... \
ghcr.io/jina-ai/reader:ossDo pracy nad samym kodem potrzebny jest Node.js w wersji 22 lub nowszej — starsze nie zbudują projektu. Opcjonalnie Docker (lokalne MinIO wstaje przez docker compose up -d, konsola na porcie 9001) i LibreOffice, jeśli chcesz testować dokumenty Office. Testy chodzą na wbudowanym runnerze Node — bez Jesta i bez Vitesta — przez npm run test:unit, npm run test:e2e i npm test.
Jeden szczegół potrafi zaskoczyć przy pierwszym buildzie ze źródeł: część zasobów nie może być redystrybuowana razem z kodem — bazy GeoLite od MaxMind, fonty CJK, listy identyfikatorów przeglądarek — i pobiera się je osobno przez npm run assets:download.
Czego wersja otwarta nie robi
Gałąź open source jest tym samym kodem, który obsługuje r.jina.ai, minus warstwa SaaS. Praktyczne konsekwencje:
- brak warstwy MongoDB, a więc brak limitowania żądań i indeksowania cache po stronie aplikacji,
- funkcje dostawców zewnętrznych wymagają własnych kluczy — wyszukiwanie (SERP), proxy rezydencjalne i opis obrazów przez model wizyjny to integracje konfigurowane zmiennymi środowiskowymi, nie coś, co obraz ma w środku,
- mechanizmy ograniczania nadużyć — filtrowanie podejrzanych adresów, limitowanie zapytań współbieżnych, odciążanie przy nadmiernym ruchu na jeden adres — są opisane w dokumentacji jako element usługi, nie wersji otwartej.
Innymi słowy: self-hosting daje pełną kontrolę nad ekstrakcją treści, ale wszystko, co odpowiada za obronę tej usługi przed ruchem z zewnątrz, musisz zorganizować sam.
Otwarte zgłoszenie SSRF — przeczytaj przed wystawieniem instancji
To jest fragment, dla którego warto było czytać do tego miejsca. W czerwcu 2026 zgłoszono w repozytorium podatność typu SSRF (Server-Side Request Forgery) w wersji uruchamianej samodzielnie, zgłoszenie #1252, i w chwili pisania tego wpisu pozostaje otwarte.
Mechanizm w skrócie: Reader sprawdza podany adres raz, przed pobraniem, odrzucając adresy IP spoza puli publicznych. Później podąża za przekierowaniami HTTP bez ponownej walidacji na każdym skoku. Wystarczy więc publiczny adres pod kontrolą atakującego, który odpowie przekierowaniem 30x na adres w sieci wewnętrznej albo na punkt metadanych dostawcy chmury — a treść spod tego adresu wróci w odpowiedzi. Zgłaszający opisuje, że dotyczy to obu ścieżek pobierania (lekkiej i przeglądarkowej) i że w warunkach testowych udało się w ten sposób wyprowadzić wewnętrzny sekret.
Instancja Readera postawiona u siebie i przyjmująca adresy od niezaufanych użytkowników to, dopóki to zgłoszenie jest otwarte, sposób na oddanie każdemu chętnemu prawa do wykonywania żądań HTTP z wnętrza Twojej sieci. Nie chodzi o teoretyczne ryzyko odległej klasy — chodzi o punkt metadanych chmury, panele administracyjne bez uwierzytelniania i usługi wewnętrzne widoczne tylko z prywatnej podsieci.
Co z tym zrobić, jeśli mimo wszystko chcesz uruchomić Reader lokalnie:
- Ogranicz ruch wychodzący kontenera na poziomie sieci. To jedyne zabezpieczenie niezależne od kodu aplikacji: własna sieć Dockera, reguły zaporowe blokujące pule prywatne (
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16) i wymuszenie wyjścia przez proxy, które te adresy odrzuca, - Zablokuj punkt metadanych dostawcy chmury (
169.254.169.254), a jeśli platforma to umożliwia — wymuś wersję drugą usługi metadanych, wymagającą tokenu, - Nie przyjmuj adresów od użytkowników bez listy dozwolonych domen. Przy pobieraniu z kilku znanych serwisów lista dozwolonych jest prosta do napisania i zamyka problem u źródła,
- Nie wystawiaj instancji do internetu bez uwierzytelniania. Obraz nie ma własnej warstwy autoryzacji, więc musi ją dodać odwrotne proxy,
- Jeśli powyższe brzmi jak dużo pracy — użyj usługi
r.jina.ai. W wariancie hostowanym to ryzyko jest po stronie dostawcy i dotyczy jego sieci, nie Twojej.
Licencje: kod jest otwarty, modele nie
Tu trzeba rozdzielić dwie rzeczy, bo mieszają się w komunikacji projektu i mogą wprowadzić w błąd przy wdrożeniu komercyjnym.
Kod Readera jest na licencji Apache-2.0. To licencja permisywna, z wyraźnym udzieleniem praw patentowych — bez zastrzeżeń przy użyciu komercyjnym, także w oprogramowaniu zamkniętym i u klienta. Z punktu widzenia agencji jest to najwygodniejszy możliwy wariant.
Modele używane przez Reader — ReaderLM-v2 i jina-vlm — są na licencji CC-BY-NC 4.0, która nie jest licencją open source i wprost wyklucza użycie komercyjne. Dotyczy to eksperymentalnego silnika konwersji HTML-a przez model językowy i opisywania obrazów. Od 10 sierpnia 2026 licencję komercyjną na te modele sprzedaje osobno Elastic, jako własną pozycję w cenniku; przez ten sam kanał idą wdrożenia lokalne w postaci samodzielnych kontenerów offline oraz zamówienia wymagające formalnej procedury zakupowej.
Praktyczny wniosek jest prosty i wart zapamiętania: komercyjne korzystanie z Readera we własnej infrastrukturze jest w porządku, dopóki nie uruchamiasz modeli Jiny lokalnie. Domyślna ścieżka konwersji — headless Chrome, @mozilla/readability i reguły w stylu turndown — nie dotyka modeli w ogóle i podlega wyłącznie Apache-2.0. Sięgnięcie po ReaderLM albo opisywanie obrazów lokalnie zmienia sytuację prawną i wymaga rozmowy z działem sprzedaży Elastica.
Korzystanie z hostowanej usługi r.jina.ai tego problemu nie ma — płacisz za wynik, a licencja modeli po stronie dostawcy jest jego sprawą.
Stan projektu
Liczby i fakty, na podstawie których warto podejmować decyzję:
- około 11,9 tys. gwiazdek i 876 forków, kod w TypeScripcie, licencja Apache-2.0,
- repozytorium powstało w kwietniu 2024, ostatnie commity z 22 maja 2026 — poprawki w formatowaniu markdownu, obsłudze proxy i wykrywaniu momentu, w którym strona przestaje się zmieniać,
- brak wydań oznaczonych tagiem — obraz dystrybuowany jest pod tagiem
oss, więc numeru wersji do przypięcia po prostu nie ma. Jeśli zależy Ci na powtarzalności wdrożeń, przypnij obraz po sumie kontrolnej (@sha256:...), - 28 otwartych zgłoszeń, w tym opisana wyżej podatność SSRF,
- w kwietniu 2026 gałąź otwarta została ponownie zsynchronizowana z kodem usługi, a warstwa MongoDB usunięta na rzecz trybu bezstanowego z opcjonalnym cache w S3.
Kontekst właścicielski: Elastic przejął Jina AI 9 października 2025. Dotychczasowy prezes Jiny został wiceprezesem do spraw AI w Elasticu i nadal prowadzi zespół pracujący nad modelami wektorowymi, rerankerami i Readerem, a firma zapowiedziała kontynuację publikowania modeli. Praktyczny ślad tej zmiany widać już w licencjonowaniu — komercyjne licencje na modele i wdrożenia lokalne przeszły do Elastica.
Nasza ocena: to jest projekt utrzymywany, ale rozwijany przede wszystkim jako zaplecze usługi. Rytm commitów jest nierówny, wydań brak, a zgłoszenia bywają otwarte miesiącami. Przy korzystaniu z hostowanego API nie ma to znaczenia. Przy wdrożeniu własnym oznacza, że jesteś odpowiedzialny za bezpieczeństwo instancji w większym stopniu, niż sugerowałaby popularność projektu.
Podsumowanie
Jina Reader zdejmuje z projektu cały etap zamiany strony internetowej na tekst nadający się do podania modelowi — i robi to na tyle prosto, że próg wejścia to jedno żądanie HTTP.
Co dostajesz:
- Prefiks zamiast integracji —
https://r.jina.ai/<URL>działa zcurl-a, z fasadyHttpw Laravelu i z każdego innego klienta HTTP, bez SDK i bez rejestracji, - obsługę stron renderowanych JavaScriptem przez headless Chrome, PDF-ów przez PDF.js i dokumentów Office przez LibreOffice, jedną ścieżką,
- kilkadziesiąt nagłówków sterujących ekstrakcją — od wskazania selektorem konkretnego fragmentu strony, przez wybór momentu uznania jej za gotową, po usuwanie odnośników i obrazów, które przy rozliczeniu za tokeny wyjścia przekłada się wprost na rachunek,
- dzielenie treści po nagłówkach albo blokach — gotowe fragmenty do indeksu wektorowego, bez własnego splittera tnącego zdania w połowie,
s.jina.ai— wyszukiwanie z pobraniem treści wyników w jednym żądaniu, z opcją zawężenia do wskazanych domen,- tryb JSON z tytułem, adresem, treścią i licznikiem zużytych tokenów, wygodniejszy w kodzie niż surowy markdown,
- możliwość uruchomienia u siebie jedną komendą Dockera, z opcjonalnym cache w magazynie zgodnym z S3.
O czym pamiętać: bez klucza limit wynosi 20 zapytań na minutę, a s.jina.ai bez klucza nie działa w ogóle. Rozliczenie r.jina.ai idzie od tokenów odpowiedzi, więc przycinanie treści to realna oszczędność; s.jina.ai kosztuje ryczałtem od 10 000 tokenów za zapytanie. Nowy klucz dostaje 10 milionów tokenów wspólnych dla wszystkich usług Jiny. W wersji uruchamianej samodzielnie nie ma warstwy uwierzytelniania ani limitowania, obraz nie ma numerowanych wydań (tag oss), a otwarte zgłoszenie SSRF #1252 sprawia, że instancji przyjmującej adresy od niezaufanych użytkowników nie wolno postawić bez ograniczenia ruchu wychodzącego i listy dozwolonych domen.
Licencja: kod Readera jest na Apache-2.0 — bez zastrzeżeń przy użyciu komercyjnym, również w produkcie zamkniętym i u klienta. Ale modele ReaderLM-v2 i jina-vlm mają licencję CC-BY-NC 4.0, zakazującą użycia komercyjnego; licencję komercyjną na nie oraz na wdrożenia lokalne sprzedaje od 10 sierpnia 2026 Elastic, osobno. Domyślna ścieżka konwersji z modeli nie korzysta, więc komercyjny self-hosting jest w porządku — pod warunkiem że świadomie zostawisz silniki modelowe wyłączone.