# Por qué un proxy request se quedó sin intentos

> URL: https://foura.ai/es/docs/troubleshooting/proxy-attempt-report
> Updated: 2026-09-30
> Index: https://foura.ai/llms.txt

## El problema

Una llamada de `POST /api/proxy/` devuelve un error y ningún dato. El mensaje es corto y siempre tiene la misma estructura:

```json
{
  "error": "Download maxTry limit reached",
  "total": 34.812,
  "request": { "...": "..." }
}
```

Esa frase se lee idéntica ya sea que cada salida estuviera bloqueada, cada salida estuviera muerta, o que FourA haya obtenido la página real en casi todos los intentos y tus propias reglas de `validate` la hayan descartado. Esos tres casos requieren soluciones opuestas.

## La respuesta: `attemptReport`

Cada llamada de Proxy que ejecutó sus intentos y falló incluye un objeto `attemptReport` junto al error, incluso una que finalizó con `"error": "Timeout"`. Un nombre de host que no se resuelve falla antes de cualquier intento, con `status: 0` y sin reporte. Cuenta con qué se encontraron realmente los intentos:

```json
{
  "error": "Download maxTry limit reached",
  "attemptReport": {
    "total": 25,
    "noResponse": 0,
    "defense": 0,
    "contentRejected": 25,
    "statusRejected": 0,
    "other": 0,
    "vendors": [],
    "profilesTried": ["default"],
    "summary": "25 attempt(s): 25 returned HTTP 200 with no defense present and were rejected only by your validate.data - the page was fetched, your content rule did not match it"
  },
  "total": 34.812
}
```

La cadena `error` se mantiene deliberadamente sin cambios, de modo que un cliente que coincida con ella siga funcionando. Lee `attemptReport.summary` para obtener una respuesta en una sola línea, o los conteos cuando quieras bifurcar según ellos.

### Campos

| Campo | Tipo | Qué cuenta |
|-------|------|------------|
| `total` | integer | Intentos realizados |
| `noResponse` | integer | La salida nunca respondió, o el sitio no respondió a tiempo |
| `defense` | integer | El sitio respondió y se reconoció un proveedor de bot-check en esa respuesta |
| `contentRejected` | integer | HTTP 200, sin bot check, rechazado únicamente por tu `validate.data` |
| `statusRejected` | integer | El sitio respondió, sin bot check, rechazado por tu `validate.status` |
| `other` | integer | Respondió, y ninguno de los anteriores |
| `vendors` | string[] | Cada proveedor de bot-check reconocido en cualquier parte de la tarea |
| `profilesTried` | string[] | Los perfiles de navegador que envió la tarea, en orden de primer uso. `default` significa que la request se envió exactamente como la escribiste. |
| `summary` | string | Una oración construida a partir de los conteos. Seguro para registrar en logs o mostrar a un usuario. |

## Cómo leerlo

### `contentRejected` es alto

Las páginas llegaron. Tu regla `validate.data` no coincidió con ellas.

Este es el caso que tú mismo puedes solucionar, y es el que cualquier otra señal oculta: las requests parecen fallos en todas las métricas, mientras FourA estuvo entregando contenido real todo el tiempo. Obtén la página una vez a través de `POST /api/single/` sin ningún `validate`, mira lo que realmente se devuelve y reescribe la regla en base a ello.

Una causa común es aplicar una sola regla a un conjunto de páginas que no son todas iguales. Un selector que existe en las páginas de artículos y no en las de videos falla cada vez que cae en una página de video, indefinidamente y con el costo total.

### `statusRejected` es alto

El sitio respondió y tu regla `validate.status` la rechazó. Si esos estados son 401, 403, 429 o 503, el sitio está rechazando al cliente en lugar de indicar que la página no existe. Prueba:

- Otro perfil de navegador (`browser`, `os`, `version` en el objeto interno `request`)
- `exitCountries` si el contenido tiene bloqueo regional
- `POST /api/browser/` si el rechazo requiere JavaScript para resolverse

### `defense` es alto

Se reconoció un bot check en las respuestas, y `vendors` indica cuál. Consulta [Site checks](https://foura.ai/docs/api/site-checks) para ver qué resuelve FourA actualmente y qué solo reporta. Si el proveedor no es uno de los que se resuelven en este endpoint, mueve la llamada a `POST /api/browser/` o `POST /api/auto/`.

### `noResponse` es alto

Las salidas no respondieron en absoluto, por lo que no se obtuvo información sobre el destino. Aumenta `maxTries`, aumenta `timeout_ms` y verifica que la URL resuelva desde la internet pública.

### `other` es alto

El sitio respondió con un estado, no se reconoció ningún bot check y el intento falló por otra razón, como una regla `validate.headers`. Un destino más lento que tu `timeout_ms` cuenta bajo `noResponse`.

## Rotación de perfiles de navegador

Cuando un sitio rechaza el navegador enviado por FourA, Proxy deja de insistir con él y prueba otra familia del [catálogo público de perfiles](https://foura.ai/docs/api/endpoints). Esto no cuesta ningún intento adicional: la rotación cambia lo que envía un reintento, nunca si este se realiza o no.

Proxy también recuerda, por sitio, la última familia que funcionó allí después de que el sitio rechazara la predeterminada. Una request posterior a ese sitio puede comenzar con esa familia desde su primer intento, y FourA pasa a la siguiente familia una vez que el sitio comienza a rechazar esa también. Solo se recuerda un navegador móvil para un sitio que responde JSON.

`profilesTried` es la forma en que ves cómo sucede. Una sola entrada significa que cada intento envió el mismo navegador: `default` es la request tal como fue escrita, y un ID de catálogo es la familia que FourA ya había aprendido para ese sitio. Varias entradas significan que la rotación se ejecutó y el sitio rechazó cada una de ellas, lo cual es una situación diferente a no haber rotado en absoluto.

En una response **exitosa** de Proxy, aparece un campo `profile` solo cuando la rotación eligió un navegador que no solicitaste:

```json
{
  "status": 200,
  "data": "<!doctype html>...",
  "proxy": "A1B2C3",
  "profile": "...",
  "total": 4.108
}
```

El valor es un ID de catálogo de `GET /api/profiles`. Si está ausente, significa que la request se envió exactamente como se escribió. Si está presente, significa que el navegador que funcionó no fue el que indicaste, así que pasa ese ID como `profile` en las siguientes llamadas en lugar de repetir el que falló. El [Playground](https://foura.ai/docs/dashboard/playground) del dashboard hace esto por ti con **Carry**.

Un `profile`, `browser`, `os` o `version` explícito en tu request nunca se anula. Tampoco se anula una request que incluya tu propio header `User-Agent` o `Cookie`, ya que una autorización está vinculada a la firma que la obtuvo.

## Leerlo en el código

```python
import requests

API = "https://eu.api.foura.ai"
H = {"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"}

r = requests.post(f"{API}/api/proxy/", headers=H, json={
    "maxTries": 5,
    "request": {
        "method": "GET",
        "url": "https://example.com/product/42",
        "validate": {"data": {"accept": ["Add to cart"]}},
    },
}).json()

if "error" in r:
    rep = r.get("attemptReport", {})
    print(rep.get("summary", r["error"]))

    if rep.get("contentRejected", 0) > rep.get("total", 0) / 2:
        # The pages arrived. The validate rule is what threw them away.
        raise SystemExit("validate.data did not match the real page")
    if rep.get("defense", 0):
        print("bot check met:", ", ".join(rep.get("vendors", [])))
```

## Relacionado

- [Endpoints de la API](https://foura.ai/docs/api/endpoints): La referencia completa de request y response del Proxy
- [Comprobaciones del sitio](https://foura.ai/docs/api/site-checks): Proveedores, `defense` y reproducción de una autorización
- [Resultados de solicitudes](https://foura.ai/docs/api/outcomes): Cómo se clasifica y factura una respuesta rechazada
- [Problemas comunes](https://foura.ai/docs/troubleshooting/common-issues): Otros problemas y sus soluciones
- [Elegir el endpoint adecuado](https://foura.ai/docs/guides/choosing-task-type): Cuándo el Proxy no es la herramienta correcta
