Typowe problemy

Rozwiązania najczęstszych problemów podczas korzystania z API FourA.

Pusta lub niekompletna zawartość

Objaw: API zwraca status 200, ale pole data jest puste lub brakuje w nim oczekiwanej zawartości.

Przyczyna: Strona docelowa używa JavaScript do renderowania treści po początkowym załadowaniu strony.

Rozwiązanie: Przełącz się ze standardowego endpointu na endpoint przeglądarkowy. Użyj checkText, aby zweryfikować, czy zawartość została załadowana:

curl -X POST https://eu.api.foura.ai/api/browser/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/products",
    "timeout_ms": 15000,
    "checkText": "product-list"
  }'

Uwaga: endpoint browser zwraca zawartość w polu body (a nie data).

403 Forbidden lub strony weryfikacji

Objaw: API zwraca HTML zawierający stronę weryfikacji lub stronę odmowy dostępu.

Przyczyna: Strona docelowa wykryła request jako zautomatyzowany i go zablokowała.

Rozwiązanie: Użyj endpointu proxy do automatycznej rotacji IP:

curl -X POST https://eu.api.foura.ai/api/proxy/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "maxTries": 5,
    "request": {
      "method": "GET",
      "url": "https://example.com/prices",
      "unblocker": true
    }
  }'

Jeśli problem nadal występuje, zwiększ maxTries, aby dać rotacji proxy więcej prób.

Błąd 403 zwrócony przez cel docelowy dociera jako HTTP 200 z status: 403 w ciele odpowiedzi. Błąd 403 samego wywołania, z nagłówkiem X-FourA-Limit, to inna sytuacja: zobacz 403 Not in Your Plan.

Błędy przekroczenia limitu czasu

Objaw: Żądania kończą się błędem przekroczenia limitu czasu (timeout).

Przyczyna: Ładowanie strony docelowej trwa dłużej niż skonfigurowany limit czasu.

Rozwiązanie: Zwiększ timeout_ms (domyślnie 15 s dla single, 30 s dla browser, 45 s dla proxy):

curl -X POST https://eu.api.foura.ai/api/browser/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://slow-site.com",
    "timeout_ms": 60000
  }'

W przypadku żądań przeglądarki upewnij się również, że wartość checkText rzeczywiście pojawia się na stronie. Literówka powoduje niepowodzenie wywołania z błędem checkText:<your text> not found.

403 Poza Twoim planem

Objaw: API zwraca kod 403 z nagłówkiem X-FourA-Limit oraz polem reason o wartości plan_limit_feature lub plan_limit_premium.

{
  "error": "Geo targeting (the exitCountries parameter) is not included in your plan (Free). Remove the parameter or upgrade.",
  "reason": "plan_limit_feature",
  "documentation": "https://foura.ai/prices"
}

Przyczyna: Twój plan nie obejmuje wywołanego endpointu lub przesłanego parametru. plan_limit_feature dotyczy wykluczonego endpointu oraz exitCountries bez targetowania geo; plan_limit_premium obejmuje exitClass: premium bez wyjść premium. Cel nie został wywołany i żadne środki nie zostały pobrane.

Rozwiązanie: Usuń parametr, wywołaj endpoint dostępny w Twoim planie lub zmień plan na wyższy. Karta Limits & Features w sekcji Usage & Limits zawiera listę funkcji dostępnych w Twoim planie. Nie ponawiaj żądania bez zmian: nagłówek Retry-After nie jest ustawiany, ponieważ czekanie nie zmieni rezultatu.

429 Too Many Requests

Objaw: API zwraca 429.

Przyczyna: Jedna z dwóch weryfikacji odrzuciła wywołanie, a odpowiedź wskazuje która. Jeśli zawiera nagłówek X-FourA-Limit, osiągnięto jeden z limitów Twojego planu: jednoczesne requesty lub liczbę requestów na minutę dla danego endpointu, dzienne requesty Browser, albo kredyty bądź transfer w bieżącym okresie rozliczeniowym. Jeśli nagłówka brak, wyczerpał się współdzielony minutowy limit platformy dla tej usługi, co wynika z ogólnego ruchu FourA, a nie Twojego.

Rozwiązanie: Najpierw sprawdź X-FourA-Limit. Odczekaj, gdy limit resetuje się za kilka sekund, i przerwij żądania, gdy tak nie jest. Limity planu, które resetują się po odczekaniu, zwracają liczbę sekund w nagłówku Retry-After oraz w retry_after_seconds; limit współdzielony zwraca je w retryAfter:

import time
import requests

# Plan limits that come back in hours or days, not seconds.
STOP_ON = {"plan_limit_browser_daily", "plan_limit_credits", "plan_limit_bandwidth"}

def make_request(endpoint_url, payload, retries=3):
    for i in range(retries):
        resp = requests.post(
            endpoint_url,
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json=payload
        )
        if resp.status_code == 429:
            limit = resp.headers.get("X-FourA-Limit")
            if limit in STOP_ON:
                raise Exception(f"stopped by {limit}: {resp.json().get('error')}")
            header = resp.headers.get("Retry-After")
            body = resp.json()
            wait = (
                int(header) if header and header.isdigit()
                else body.get("retry_after_seconds") or body.get("retryAfter") or 2 ** i
            )
            time.sleep(wait)
            continue
        return resp
    raise Exception("Rate limit not resolved after retries")

# Example: single request
make_request(
    "https://eu.api.foura.ai/api/single/",
    {"method": "GET", "url": "https://example.com"}
)

Jeśli nagłówek zawierał plan_limit_concurrency lub plan_limit_rate, rozwiązaniem jest ograniczenie liczby jednocześnie otwartych wywołań oraz liczby wywołań uruchamianych na minutę, zamiast agresywnego ponawiania prób. Natychmiastowe ponowne wysłanie odrzuconej partii spowoduje ponowne odrzucenie całej partii. Odrzucone wywołania nie wliczają się do limitu na minutę, ale jeśli nadal napływają w tempie przekraczającym dwukrotność tego limitu, odrzucenia zamieniają się w cooldown: treść odpowiedzi 429 zawiera cooldown: true i wymaga wstrzymania na 30 sekund (retry_after_seconds: 30). Sekcja Run Requests in Parallel opisuje ten wzorzec, a zakładka Usage & Limits w Dashboard pokazuje bieżące liczniki obok Twoich limitów.

503 Service Unavailable

Objaw: API zwraca status 503.

Przyczyna: Zdarza się to w dwóch przypadkach:

  1. Usługa osiągnęła pełną wydajność. FourA przetwarza już maksymalną dozwoloną liczbę żądań na danym silniku jednocześnie, liczoną dla całego ruchu, a nie tylko Twojego. Service at capacity w polu error. Zazwyczaj ustępuje w ciągu kilku sekund.
  2. Usługa tymczasowo wyłączona. Trwa okno serwisowe. Service disabled w polu error.

W obu przypadkach odpowiedź zawiera pole retryAfter. Żaden z nich nie wynika z limitu planu: limity Twojego planu zawsze zwracają nagłówek X-FourA-Limit przy kodzie 403 lub 429, nigdy przy 503.

Rozwiązanie: Odczekaj retryAfter s, a następnie ponów próbę:

import time
import requests

def make_request_with_retry(endpoint_url, payload, retries=3):
    for i in range(retries):
        resp = requests.post(
            endpoint_url,
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json=payload
        )
        if resp.status_code in (429, 503):
            header = resp.headers.get("Retry-After")
            body = resp.json()
            wait = (
                int(header) if header and header.isdigit()
                else body.get("retry_after_seconds") or body.get("retryAfter") or 2 ** i
            )
            time.sleep(wait)
            continue
        return resp
    raise Exception("Request not resolved after retries")

Kod 503 z powodu obciążenia oznacza, że FourA jest zajęte, więc wycofanie się i ponowienie próby w zupełności wystarczy. Jeśli otrzymujesz odmowę z kodem 429 i X-FourA-Limit, problem leży po Twojej stronie: zmniejsz liczbę równoległych żądań w swoim potoku.

504 Upstream Timeout

Objaw: API zwraca 504 z {"error": "Upstream timeout"}.

Przyczyna: Zadanie nie zakończyło się w budżecie czasowym zadeklarowanym dla żądania. Wolny cel, rozwiązywanie zabezpieczeń na zimno lub bardzo duża strona mogą to spowodować. Nie jest to problem z Twoim kluczem, parametrami ani proxy.

Rozwiązanie: Daj wywołaniu więcej czasu lub ponów próbę. FourA czeka przez czas określony w timeout_ms plus niewielki margines, więc zwiększenie tej wartości rzeczywiście wydłuża czas oczekiwania:

{
  "url": "https://slow-site.com/report",
  "timeout_ms": 90000
}

W przypadku /api/auto/ na chronionym celu, pierwsze wywołanie na zimno może zająć kilkadziesiąt sekund. Jego timeout_ms obejmuje całą ścieżkę i akceptuje do 180000.

Gdy samemu /api/auto/ wyczerpie się ten budżet, wywołanie nadal zwraca HTTP 200. Treść zawiera error zaczynający się od time budget exhausted, a status to zazwyczaj 504 (wcześniejsza nieudana próba może pozostawić tam swój własny status). Zwiększ timeout_ms lub ponów próbę.

502 Upstream Unavailable

Objaw: API zwraca 502 z {"error": "Upstream unavailable"} lub 503 z {"error": "Backend service unavailable"}.

Przyczyna: FourA połączyło się z własnym silnikiem, ale nie mogło użyć odpowiedzi, zazwyczaj z powodu restartu instancji.

Rozwiązanie: Ponów próbę z krótkim opóźnieniem (backoff). Oba przypadki są klasyfikowane jako service_error, a rozliczane jest tylko success, więc ponowna próba nic dodatkowo nie kosztuje. Jeśli problem trwa dłużej niż minutę lub dwie, sprawdź stronę statusu.

401 Błędy uwierzytelniania

Objaw: Każde żądanie zwraca 401 Unauthorized.

Lista kontrolna:

  1. Upewnij się, że nagłówek to X-API-Key: YOUR_API_KEY (nie Authorization: Bearer ani Api-Key)
  2. Sprawdź, czy w kluczu API nie ma dodatkowych spacji lub znaków nowej linii
  3. Wygeneruj nowy klucz w Dashboardzie, jeśli obecny mógł zostać skompromitowany

400 Cel wskazuje na prywatny lub zarezerwowany adres IP

Objaw: API zwraca 400 z Refusing to fetch <target>: target resolves to a private or reserved IP range zanim żądanie opuści FourA.

Przyczyna: Twój url wskazuje na prywatny, pętli zwrotnej (loopback) lub zarezerwowany zakres adresów IP (RFC 5735, RFC 6598 lub zarezerwowane bloki IPv6). FourA odrzuca takie cele, aby jego sieć nie mogła być wykorzystana do uzyskania dostępu do hostów wewnętrznych.

Rozwiązanie: Pobierz publiczny URL. Jeśli testujesz, użyj publicznego celu, takiego jak https://example.com lub https://httpbin.org/get. Jeśli docelowym adresem jest usługa, którą sam uruchamiasz, udostępnij ją najpierw pod publiczną nazwą hosta.

{ "error": "Refusing to fetch <target>: target resolves to a private or reserved IP range. The FourA scraping API only forwards requests to public internet hosts." }

Nazwa hosta, której nie można rozwiązać, nie jest odrzucana. Wywołanie zwraca HTTP 200 z status: 0 oraz powodem (could not resolve <host>: <reason>), podobnie jak w przypadku każdego celu, do którego FourA nie może dotrzeć, i nie podlega rozliczeniu.

no_eligible_proxy podczas używania exitCountries

Objaw: Wywołanie /api/proxy/ z exitCountries zwraca HTTP 200 z błędem w formacie JSON:

{
  "error": "No eligible proxy found for exit countries: CZ, GB",
  "code": "no_eligible_proxy",
  "details": { "exitCountries": ["CZ", "GB"] },
  "total": 0.084
}

Przyczyna: Obecna pula proxy nie ma działającego węzła wyjściowego, którego kraj widoczny dla celu jest zgodny z Twoją białą listą. FourA nigdy nie przełącza się na niezażądany kraj, gdy ustawisz exitCountries.

Rozwiązanie: Zachowaj żądany zakres i spróbuj ponownie później. Pula jest odświeżana mniej więcej co dziesięć minut, więc kraj, który nie ma teraz dopasowania, często zyskuje je w ciągu godziny.

import time, requests

def fetch_scoped(url, countries, max_attempts=6, wait_sec=600):
    for _ in range(max_attempts):
        r = requests.post("https://eu.api.foura.ai/api/proxy/",
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json={"maxTries": 5, "exitCountries": countries,
                  "request": {"method": "GET", "url": url}}).json()
        if r.get("code") == "no_eligible_proxy":
            time.sleep(wait_sec)
            continue
        return r
    raise RuntimeError(f"no eligible exit in {countries} after {max_attempts} attempts")

Rozszerzaj listę krajów tylko wtedy, gdy wymagania Twojego workflow dotyczące lokalizacji rzeczywiście uległy zmianie. Ciche fallbacki do innych krajów mogą zaburzyć logikę zależną od geolokalizacji na dalszych etapach.

Treść odpowiedzi (body) zwraca nieczytelny tekst

Objaw: Odpowiedź data (lub body) zawiera mojibake lub nieczytelne znaki, gdy cel używa kodowania innego niż UTF-8.

Przyczyna: Domyślnie FourA automatycznie dekoduje treść odpowiedzi do UTF-8 na podstawie nagłówka Content-Type celu lub tagu HTML <meta charset>. Jeśli cel podaje nieprawidłowe informacje o zestawie znaków, otrzymasz zniekształcony tekst.

Rozwiązanie: W przypadku danych binarnych (obrazy, protobuf, surowe audio), ustaw returnBuffer: true w request. Single i Proxy zwracają wtedy data jako obiekt zawierający surowe bajty, {"type": "Buffer", "data": [<byte values>]}, bez stosowania transkodowania zestawu znaków.

{
  "method": "GET",
  "url": "https://example.com/image.png",
  "returnBuffer": true
}

W przypadku celów tekstowych z błędnie zadeklarowanym zestawem znaków (charset) zdekoduj surowe bajty samodzielnie: pobierz za pomocą returnBuffer: true, odczytaj wartości bajtów w data.data, a następnie zdekoduj je przy użyciu właściwego charsetu.

Nieoczekiwany kod HTML zamiast JSON

Objaw: Oczekiwano formatu JSON z witryny docelowej, ale otrzymano HTML.

Przyczyna: Strona docelowa może zwracać inną zawartość w zależności od nagłówków.

Rozwiązanie: Dodaj header Accept i włącz unblocker, aby uzyskać realistyczne nagłówki przeglądarki:

curl -X POST https://eu.api.foura.ai/api/single/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "GET",
    "url": "https://api.example.com/data",
    "headers": [["Accept", "application/json"]],
    "unblocker": true
  }'

Możesz także ustawić tryJsonData na true, aby FourA automatycznie przetwarzało odpowiedzi JSON.

Treść to strona z testem botów, a nie zawartość

Objaw: Wywołanie powiodło się, status ma wartość 200, ale data (lub body) to weryfikacja bota, a nie docelowa strona.

Przyczyna: Cel uruchomił weryfikację bota, którą FourA napotkało, ale nie mogło jej ominąć. Odpowiedź to potwierdza: Single i Proxy zwracają defense z solved: false, a Browser zwraca defenseSolved: false z dostawcą w defenses.present.

Rozwiązanie: Najpierw sprawdź defense.vendor, a następnie eskaluj. Wypróbuj inny profil przeglądarki w Single, przejdź na Proxy, aby zmienić adres wyjściowy, lub użyj Browser, aby uruchomić JavaScript. Pełna dokumentacja pól i lista dostawców: Weryfikacje witryn.

Dodaj fragment validate.data.accept, który zawiera tylko właściwa strona. Strona weryfikacji rozpoznana przez FourA nigdy nie jest traktowana jako sukces: jest zwracana z nagłówkiem X-FourA-Check-Page i nie podlega opłacie. Bez validate nierozpoznana przez FourA strona weryfikacji, zwrócona z kodem HTTP 200, jest liczona jako sukces, a o problemie dowiadujesz się na dalszym etapie przetwarzania zamiast podczas wywołania.

Nadal potrzebujesz pomocy?

Jeśli żadne z powyższych rozwiązań nie działa:

  1. Sprawdź stronę stanu pod kątem trwających incydentów
  2. Przejrzyj metryki swoich żądań w Panelu
  3. Skontaktuj się ze wsparciem pod adresem support@foura.ai, podając szczegóły żądania (dołącz X-FourA-Request-Id z nieudanej odpowiedzi)

Następne kroki

Aktualizacja: 30 września 2026