Navega por un verificador de backlinks por URL sin huecos ni bucles infinitos
Filas por llamada, páginas por consulta y un límite estricto de 50.000. Aquí tienes un bucle que respeta las tres condiciones y te indica cuándo detenerse.

Se devuelven hasta 1.000 filas por llamada. Cada llamada se factura una vez, independientemente del número de filas que contenga. La paginación profunda está limitada a 50.000 filas, lo que equivale a 50 llamadas de 1.000 filas cada una.
Por qué el ordenamiento precede a la paginación
Paginar sobre una lista sin ordenar es la causa de los duplicados. Envía siempre sort y order junto con page y per, para que la página 3 signifique lo mismo en cada solicitud del proceso.
Una consulta refdomains cuesta 2 créditos por llamada, por lo que 50 llamadas suman 100 créditos, o un céntimo. Incluso el peor caso es económico; el coste real es un bucle que no termina.
Elección de la columna de ordenación
La columna por la que ordenar depende de la pregunta. El orden descendente es la opción habitual para auditorías, porque el límite corta la cola larga en lugar de la parte que te interesa.
Ordena por un campo que no tenga relación con tu pregunta y el corte podría eliminar las filas que necesitabas. Extrae diez filas con cada ordenación candidata y observa qué fragmento sobrevive al límite.
Registra la elección en el informe, para que la siguiente persona sepa por qué el corte se situó donde lo hizo.
Registros que cambian durante una ejecución
Los datos no cambian durante una ejecución a menos que la reconstrucción mensual se ejecute a mitad del proceso. Es poco frecuente, pero real. Un trabajo nocturno que se solape con el primero del mes puede devolver una página del índice antiguo y la siguiente del nuevo, así que registra la hora de inicio en tu registro y compara.
Escribe la hora de inicio en la parte superior del registro y el número de página en cada línea. Así, una discrepancia en la salida indicará un problema de sincronización, no un error de análisis.
Si el trabajo está programado, evita una hora de inicio justo antes de una reconstrucción probable. Tus registros muestran una reconstrucción como un cambio en los totales entre dos ejecuciones que coinciden en lo demás, así que incluye los totales en cada línea del registro.
Una ejecución que abarca una reconstrucción no es errónea por defecto. Solo es inconsistente, así que marca esas ejecuciones en el registro y vuelve a ejecutar el fragmento afectado cuando sea relevante para un informe.
Un bucle de paginación que termina
TypeScript para un worker de Node 20. Se detiene en la primera página corta, en el límite o en cualquier ok que no sea verdadero.
const BASE = "https://seomasters.dev/api.php";
const CAP = 50_000;
const PER = 1000;
export async function pullAll(domain: string, key: string) {
const rows: unknown[] = [];
for (let page = 1; rows.length < CAP; page++) {
const u = new URL(BASE);
u.search = new URLSearchParams({
action: "refdomains", q: domain,
page: String(page), per: String(PER),
sort: "dr", order: "desc",
}).toString();
const res = await fetch(u, { headers: { Authorization: `Bearer ${key}` } });
if (res.status === 401 || res.status === 402) throw new Error(`stop: HTTP ${res.status}`);
const body = await res.json();
if (!body.ok) throw new Error(JSON.stringify(body).slice(0, 300));
const chunk = findRows(body); // see note below
rows.push(...chunk);
if (chunk.length < PER) break; // short page means we are done
}
return rows;
}Solución de problemas en una ejecución de paginación
| Lo que ves | Posible causa | Qué hacer |
|---|---|---|
| La página 51 devuelve vacío o error | Has alcanzado el límite de 50.000 | Refina con otra acción o un sort diferente, luego fusiona por id |
| Mismo dominio en dos páginas | Consulta sin ordenar o reconstrucción del índice a mitad de ejecución | Envía sort y order; elimina duplicados por la clave de dominio |
| Menos filas que el total del panel | El total es para todo el grafo, la extracción está limitada | Muestra "top 50.000" en la interfaz |
| Bucle infinito | La condición solo verifica rows.length | Rompe en una página corta, como se indica arriba |
| Factura superior a la esperada | Reintenta en cada respuesta distinta a 200 | Reintenta solo errores de red, ver errores |

Lectura de filas sin adivinar los nombres de los campos
La función auxiliar findRows anterior se deja intencionadamente abierta. Haz una llamada real, observa el JSON y escribe el accesor según lo que veas, no según lo que prometía un tutorial.
Para el primo más económico de este trabajo, evaluar muchos dominios a la vez sin paginación, lee el script DR masivo.
Congela una respuesta como fixture
Luego congélala con una prueba. Guarda una respuesta como archivo fixture y verifica el recuento de filas y las claves de la primera fila, para que un cambio futuro falle en CI y no en el gráfico de un cliente.
Mantén el fixture en control de versiones junto a la prueba, para que un revisor vea la estructura que espera el código sin tener que ejecutar nada.
Cuando la API añada un campo más tarde, la diferencia del fixture te dirá si tu accesor lo detectó o lo ignoró silenciosamente.
Nombra el fixture según la consulta de la que proviene, como la acción, el dominio y el orden. Un archivo llamado response1.json no le dice nada al siguiente lector sobre lo que demuestra.
Cuenta las filas que almacenaste
Compara las filas que guardaste con el total que reportó el bucle. Una diferencia significa que se perdió una página, y una repetición significa que una página se extrajo dos veces y se actualizó en una sola fila.
Ejecuta esa comprobación después de cada extracción de prueba, no solo después de la primera. Una desviación en el recuento suele ser el primer síntoma de un cambio en el orden o de una reconstrucción a mitad de ejecución.
Mantén el recuento en la misma línea de registro que el número de página, para que ambos puedan leerse de un vistazo.
División del trabajo por encima del límite
Algunas preguntas superan el límite. Para listas por encima del límite, divide el problema en lugar de paginar más intensamente. Extrae los top 50.000 con un orden, luego pregunta a otras acciones sobre los dominios más relevantes, ya que también cuestan 2 créditos y responden a preguntas diferentes. Paginar más intensamente nunca supera el corte.
Extrae los top 50.000 con un orden
Acepta el límite como un hecho de la API. Extrae los top 50.000 filas con un orden, guárdalas y etiqueta el resultado como el fragmento superior en cualquier informe.
Un panel que muestra un recuento limitado como si fuera el total completo engaña a las personas que lo leen. La etiqueta no tiene coste, y un informe de verificador de backlinks por URL se lee con mayor honestidad con ella.
Decide el tamaño del fragmento antes de la ejecución y escríbelo en la cabecera del informe, para que el número nunca parezca mayor de lo que es. Una línea de cabecera no tiene coste, y un lector que encuentre una fila faltante más tarde te lo agradecerá.
Haz una pregunta diferente a los dominios más relevantes
anchors y toppages responden a otras preguntas, como qué texto ancla domina o qué páginas atraen los enlaces. Para un dominio que supera el límite, esas respuestas pueden ser más importantes que la siguiente página de la misma lista.
Mantén sus resultados en sus propias tablas, indexadas por el dominio, para que una extracción posterior del mismo dominio pueda reemplazarlas sin tocar las filas del fragmento superior.
Cada acción extra cuesta sus propios créditos, así que calcúlalo antes de la ejecución, no después de que llegue la factura.
Una lista corta de los dominios más pesados, extraída una vez al mes, a menudo da un contexto más útil que una lista más larga extraída todas las noches.
Fusión por la clave de dominio
Cuando dos extracciones se solapan, fusionalas por la clave de dominio y conserva la marca de tiempo más reciente. La fusión entonces no depende de qué extracción terminó primero.
Registra qué extracción ganó cada fila. Si un número cambia entre dos informes, ese registro te dirá si cambió el índice o la fusión.
Mantén la fusión en una sola función con una prueba, ya que es el único lugar donde se encuentran dos extracciones.
Reanudación tras un fallo
Los fallos ocurren. Un despliegue reinicia el worker, un portátil entra en suspensión, una VPN se cae y el bucle muere en la página 31 de 50.
Guarda la página después de cada llamada
Persiste el último número de página completado después de cada llamada. Reinicia desde ese número más uno, no desde el principio, y pagarás 2 créditos por página en lugar de volver a comprar toda la extracción.
Guárdalo después de analizar la respuesta, no antes. Una página que no lograste leer debe extraerse de nuevo, y un número de página guardado debe significar siempre filas que ya tienes.
Un guardado que ocurre una vez por minuto en lugar de una vez por llamada deja una ventana donde un fallo puede repetir el gasto de créditos. Mantén la escritura pequeña, para que sea económica hacerla cada vez.
Registra también cuánto tarda cada guardado y cuánto tarda cada llamada. Un guardado que compite en tiempo con la llamada apunta a la capa de almacenamiento, y eso vale la pena corregirlo antes de que crezca el bucle.
Actualización insertada (Upsert) por la clave de dominio
Mantén una escritura idempotente. Actualiza inserta cada fila por su clave de dominio, para que una página extraída dos veces deje una fila, no dos.
Usa la misma clave en todas las vías de escritura, incluyendo el script de reparación manual. Dos vías de escritura con dos claves son la causa de que los duplicados sobrevivan a una reanudación.
Un script de reparación suele escribirse apresuradamente, tras una ejecución fallida. Es entonces cuando se introduce una segunda clave, así que revísalo con el mismo cuidado que el bucle principal.
Rechaza una reanudación si cambió el orden
Registra el orden y el sentido junto al número de página. Si alguien cambia sort entre un fallo y el reinicio, el número de página guardado ya no significa el mismo fragmento. Rechaza la reanudación y empieza de cero.
Almacena un pequeño registro de reanudación con el orden, el sentido, la página y la hora. El bucle lee ese registro primero y se niega a continuar si algún campo ya no coincide con la solicitud que está a punto de hacer.
Una reanudación rechazada no es un fallo. Es el bucle diciendo que la página guardada ya no significa las mismas filas, y empezar de cero es el error más barato.
Ejecución del bucle en producción
- 1
Empieza con un dominio pequeño
Ejecuta el bucle contra un dominio con unas pocas cientos de filas, para que se active la parada en página corta y puedas observar cómo funciona la ruta de salida.
- 2
Verifica una página a ojo
Abre una respuesta almacenada y confirma que el accesor sigue leyendo las filas. No confíes en un análisis que no hayas examinado.
- 3
Mantén los límites en la configuración
Pon el límite y el tamaño de página en un solo archivo de configuración, para que un cambio aparezca en la revisión y no se oculte dentro de una función.
- 4
Registra la razón por la que terminó el bucle
Registra si la ejecución terminó en una página corta, en el límite o por un error. Esas tres finalizaciones significan cosas diferentes para quien lea el registro.