# Errori, rifiuti da robots.txt e retry

> Tutti i codici di errore di WebReaderAPI: rifiuti da robots.txt, timeout ed errori sui crediti, quali riprovare e perché nessuno viene mai addebitato.

- URL: https://webreaderapi.com/it/docs/errors/
- Ultimo aggiornamento: 2026-10-22
- Editore: WebReaderAPI (https://webreaderapi.com)

Ogni errore ha uno stato HTTP, un `code` stabile e un `message` leggibile. Nessuno di essi usa un credito. Alcuni meritano un retry; i rifiuti che arrivano da un sito sono definitivi, e non li aggiriamo mai.

**Risposta rapida — Cosa significano i codici di errore di WebReaderAPI, e quali conviene riprovare?**

Gli errori **WebReaderAPI** si dividono in tre gruppi, e nessuno viene mai addebitato. I problemi di richiesta (`invalid_url`, `invalid_api_key`, `insufficient_credits`) richiedono una correzione da parte tua. Le decisioni del sito (`blocked_by_robots`, `blocked_by_site_policy`, `target_refused`) sono definitive. I fallimenti temporanei (`fetch_failed`, `fetch_timeout`, `concurrency_limit`) possono essere riprovati con backoff. I crediti partono da 0,07 USD/1K pagine, pagati in criptovalute senza KYC.

## Quali codici di errore può restituire l'API?

Il body è sempre `{"error": {"code", "message"}}`, più `target_status` quando il rifiuto è arrivato dal sito.

| HTTP | `code` | Causa | Riprovare? |
| --- | --- | --- | --- |
| 400 | `invalid_url` | Non http o https, troppo lungo, oppure un indirizzo privato, locale o di metadata cloud | No: correggi l'URL |
| 400 | `invalid_parameter` | Un parametro ha un valore fuori dal suo elenco o intervallo | No: correggi la richiesta |
| 401 | `invalid_api_key` | Chiave mancante, errata o revocata | No: controlla la chiave |
| 402 | `insufficient_credits` | Il tuo saldo non ha più crediti | Dopo aver acquistato un pack |
| 403 | `blocked_by_robots` | Il robots.txt del sito vieta la pagina a WebReaderAPI o a tutti i robot | No: definitivo |
| 403 | `blocked_by_site_policy` | Il sito dichiara `Content-Signal: ai-input=no` | No: definitivo |
| 422 | `unsupported_content` | Un tipo che non leggiamo (video, archivio) o un file troppo grande | No |
| 429 | `concurrency_limit` | Troppe delle tue richieste sono in esecuzione nello stesso momento | Sì, con backoff |
| 502 | `target_refused` | Il sito ha rifiutato: 403, 429, una pagina di challenge o un login wall; il suo stato è in `target_status` | No: definitivo |
| 502 | `fetch_failed` | Errore DNS, TLS o di connessione, oppure il sito ha risposto 404 o 410 | Una o due volte, con backoff |
| 504 | `fetch_timeout` | Il sito non ha risposto entro `timeout` | Sì, con backoff o un timeout più lungo |

## Perché robots.txt e i rifiuti del sito sono definitivi?

Perché sono una decisione del proprietario del sito e WebReaderAPI è costruito per rispettarla. Rispettiamo robots.txt: il nostro crawler si identifica come WebReaderAPI, segue le regole scritte per lui o per tutti i robot e non legge una pagina che un sito vieta. Le pagine rifiutate non vengono addebitate. Se un sito dichiara Content-Signal: ai-input=no nel suo robots.txt, non leggiamo le sue pagine per te.

Quando un sito rifiuta una richiesta in un altro modo, con un 403, un 429, una pagina di challenge o un modulo di login, ricevi `target_refused` e lo stato del sito in `target_status`. Se un sito rifiuta la nostra richiesta, restituiamo la sua risposta: non risolviamo mai CAPTCHA, non accediamo agli account e non tentiamo di aggirare un blocco o un paywall. Riprovare lo stesso URL un minuto dopo di solito dà la stessa risposta, quindi tratta questi codici come un risultato, non come un errore: registrali e vai avanti.

## Come faccio a controllare perché una pagina è stata rifiutata?

Apri il `/robots.txt` del sito e cerca un gruppo che nomina `WebReaderAPI`, oppure il gruppo `*` che vale per tutti i robot. Una riga `Disallow` che corrisponde al percorso spiega un `blocked_by_robots`. Una riga come `Content-Signal: ai-input=no` spiega un `blocked_by_site_policy`.

Conserviamo una copia di ogni robots.txt per un massimo di 24 ore. Se un sito ha appena aperto una sezione ai robot, la modifica può richiedere fino a un giorno per essere applicata. I proprietari dei siti possono leggere come si comporta il nostro crawler e come consentirlo o bloccarlo nella [nostra pagina del crawler](https://webreaderapi.com/it/bot/).

## Come devo riprovare i fallimenti temporanei?

Riprova solo `concurrency_limit`, `fetch_timeout` e, una o due volte, `fetch_failed`. Aspetta prima di ogni nuovo tentativo e raddoppia l'attesa ogni volta, con un po' di jitter casuale così i worker paralleli non riprovano insieme. Fermati dopo 4 o 5 tentativi.

Per `concurrency_limit`, la soluzione migliore è inviare meno richieste contemporaneamente: Ogni account ha un limite di pagine lette contemporaneamente; la tua dashboard lo mostra e il supporto può aumentarlo. Per `fetch_timeout`, aumenta `timeout` fino a 60 secondi prima di riprovare con un sito lento. I tentativi non costano nulla, perché un tentativo fallito non viene mai addebitato.

*Python: riprova solo gli errori che possono cambiare*

```python
import os
import random
import time

import requests

API = "https://webreaderapi.com/api/v1/read"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}
RETRY = {"concurrency_limit", "fetch_timeout", "fetch_failed"}
FINAL = {"blocked_by_robots", "blocked_by_site_policy", "target_refused", "unsupported_content"}


def read_page(url, attempts=5, **options):
    wait = 1.0
    for attempt in range(1, attempts + 1):
        resp = requests.get(API, headers=HEADERS, params={"url": url, **options}, timeout=75)
        if resp.status_code == 200:
            return resp.json()
        error = resp.json().get("error", {})
        code = error.get("code", "unknown")
        if code in FINAL:
            return {"url": url, "skipped": code, "target_status": error.get("target_status")}
        if code not in RETRY or attempt == attempts or (code == "fetch_failed" and attempt >= 3):
            raise RuntimeError(f"{code}: {error.get('message')}")
        time.sleep(wait + random.uniform(0, wait / 2))
        wait = min(wait * 2, 30)
    raise RuntimeError("unreachable")


if __name__ == "__main__":
    print(read_page("https://example.com/blog/first-post", max_chars=20000).get("title"))

```

*Node.js: la stessa regola con backoff esponenziale*

```javascript
const RETRY = new Set(['concurrency_limit', 'fetch_timeout', 'fetch_failed']);
const FINAL = new Set(['blocked_by_robots', 'blocked_by_site_policy', 'target_refused', 'unsupported_content']);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

export async function readPage(url, options = {}, attempts = 5) {
  let wait = 1000;
  for (let attempt = 1; attempt <= attempts; attempt++) {
    const params = new URLSearchParams({ url, ...options });
    const res = await fetch(`https://webreaderapi.com/api/v1/read?${params}`, {
      headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}` },
    });
    const body = await res.json();
    if (res.ok) return body;
    const code = body.error?.code ?? 'unknown';
    if (FINAL.has(code)) return { url, skipped: code, target_status: body.error.target_status };
    if (!RETRY.has(code) || attempt === attempts) throw new Error(`${code}: ${body.error?.message}`);
    await sleep(wait + Math.random() * (wait / 2));
    wait = Math.min(wait * 2, 30000);
  }
}

```

## E per gli errori dentro un batch o un crawl?

Un lavoro non si ferma perché una pagina fallisce. Quella pagina compare in `results` come `{url, error}` con gli stessi codici di cui sopra, e non costa nulla. Un crawling che incontra `blocked_by_robots` su una sezione legge semplicemente il resto del sito.

Alla fine di un lavoro, conta i codici di errore. Molti `target_refused` su un sito significano che il sito non accetta lettori automatizzati; molti `fetch_timeout` significano che è lento, e un `timeout` più lungo nelle opzioni del lavoro può aiutare.

## Errori: domande frequenti

### Mi viene addebitata una pagina bloccata da robots.txt?

No. 1 credito = 1 pagina letta senza browser; 2 crediti quando la pagina richiede un browser per eseguire JavaScript. Una richiesta che fallisce, o che il robots.txt di un sito rifiuta, non viene addebitata. Lo stesso vale per ogni altro errore in questa pagina.

### Puoi leggere una pagina che blocca il tuo crawler se te lo chiedo?

No. Rispettiamo la scelta del proprietario del sito, e la policy è la stessa per ogni cliente. Se il sito è tuo, aggiungi una regola per `WebReaderAPI` nel tuo robots.txt; la [pagina del crawler](https://webreaderapi.com/it/bot/) mostra come.

### Perché ricevo fetch_failed per una pagina che esiste?

Il sito potrebbe essere stato giù, lento ad accettare una connessione TLS o restituire 404 ai client automatizzati. Riprova una o due volte con backoff. Se continua a fallire, controlla l'indirizzo in un browser.

### Cosa dovrebbe dire il mio agente all'utente dopo un rifiuto?

Qualcosa di semplice, come che il sito non consente la lettura automatizzata di quella pagina. Poi lascia che il modello usi altre fonti. Restituire il codice di errore come risultato del tool basta per la maggior parte dei modelli.

---

WebReaderAPI: WebReaderAPI è un'API web reader per agenti AI che converte qualsiasi pagina web pubblica in Markdown pulito, con pagamento in criptovalute e senza caricare documenti d'identità. I crediti prepagati da 0,07 USD/1K pagine non scadono mai e robots.txt viene rispettato. Senza KYC — niente documento, niente selfie, niente documenti. Paga in criptovalute.
