Site crawls
Read a crawl, its pages, and the findings that repeat across a site.
A crawl follows links from a starting page and analyses everything it finds on the same site, up to your plan's page limit. Crawls are read-only through the API: start one in the dashboard, then read its results here.
Site crawl is on Pro and Agency. A key on Free or Basic gets 403 plan_excluded from these endpoints.
GET /site-crawls
List crawls
Every crawl this workspace has run, newest first.
Query parameters
| Name | Type | Notes | |
|---|---|---|---|
limit | integer | optional | 1 to 100. Defaults to 25. |
state | string | optional | One of queued, running, done, failed. |
Request
curl "https://webrankpage.com/api/v1/site-crawls" \
-H "Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c"<?php
$ch = curl_init('https://webrankpage.com/api/v1/site-crawls');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c',
],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);// Node 18+, or any server-side runtime. Never in browser code:
// an API key in a page is readable by anyone who opens it.
const response = await fetch('https://webrankpage.com/api/v1/site-crawls', {
headers: {
Authorization: `Bearer ${process.env.WEBRANKPAGE_KEY}`,
},
});
const data = await response.json();
console.log(data);import requests
response = requests.get(
'https://webrankpage.com/api/v1/site-crawls',
headers={'Authorization': 'Bearer wrp_live_8fKp2mQx9tR4vN7c'},
)
print(response.json())require 'net/http'
require 'json'
uri = URI('https://webrankpage.com/api/v1/site-crawls')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer wrp_live_8fKp2mQx9tR4vN7c'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://webrankpage.com/api/v1/site-crawls", nil)
req.Header.Set("Authorization", "Bearer wrp_live_8fKp2mQx9tR4vN7c")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]interface{}
json.NewDecoder(res.Body).Decode(&data)
fmt.Println(data)
}Response
{
"site_crawls": [
{
"id": 594,
"host": "onbixo.com",
"label": "Full crawl before the redesign",
"seed_url": "https://onbixo.com/",
"state": "done",
"pages_found": 157,
"pages_fetched": 90,
"pages_failed": 0,
"max_pages": 90,
"max_depth": 4,
"created_at": "2026-09-24T06:33:08+00:00",
"started_at": "2026-09-24T06:33:09+00:00",
"finished_at": "2026-09-24T06:35:51+00:00",
"error": null
},
{
"id": 234,
"host": "onbixo.com",
"label": "Onbixo, after the redesign",
"seed_url": "https://onbixo.com/",
"state": "done",
"pages_found": 92,
"pages_fetched": 25,
"pages_failed": 0,
"max_pages": 25,
truncated. The full response continues.
pages_found counts every URL discovered, including those skipped once the limit was reached. pages_fetched is what was actually analysed, and that is the number your plan caps.
GET /site-crawls/{id}
Read one crawl
The crawl with its totals and score distribution.
Request
curl "https://webrankpage.com/api/v1/site-crawls/594" \
-H "Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c"<?php
$ch = curl_init('https://webrankpage.com/api/v1/site-crawls/594');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c',
],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);// Node 18+, or any server-side runtime. Never in browser code:
// an API key in a page is readable by anyone who opens it.
const response = await fetch('https://webrankpage.com/api/v1/site-crawls/594', {
headers: {
Authorization: `Bearer ${process.env.WEBRANKPAGE_KEY}`,
},
});
const data = await response.json();
console.log(data);import requests
response = requests.get(
'https://webrankpage.com/api/v1/site-crawls/594',
headers={'Authorization': 'Bearer wrp_live_8fKp2mQx9tR4vN7c'},
)
print(response.json())require 'net/http'
require 'json'
uri = URI('https://webrankpage.com/api/v1/site-crawls/594')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer wrp_live_8fKp2mQx9tR4vN7c'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://webrankpage.com/api/v1/site-crawls/594", nil)
req.Header.Set("Authorization", "Bearer wrp_live_8fKp2mQx9tR4vN7c")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]interface{}
json.NewDecoder(res.Body).Decode(&data)
fmt.Println(data)
}Response
{
"site_crawl": {
"id": 594,
"host": "onbixo.com",
"state": "done",
"pages_fetched": 90,
"pages_found": 157,
"average_score": 71,
"critical_pages": 4
}
}GET /site-crawls/{id}/pages
List the pages a crawl fetched
Every page, with its score and issue counts. This is the endpoint to use for a spreadsheet of a whole site.
Query parameters
| Name | Type | Notes | |
|---|---|---|---|
limit | integer | optional | 1 to 100. Defaults to 25. |
offset | integer | optional | How many to skip. |
Request
curl "https://webrankpage.com/api/v1/site-crawls/594/pages" \
-H "Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c"<?php
$ch = curl_init('https://webrankpage.com/api/v1/site-crawls/594/pages');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c',
],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);// Node 18+, or any server-side runtime. Never in browser code:
// an API key in a page is readable by anyone who opens it.
const response = await fetch('https://webrankpage.com/api/v1/site-crawls/594/pages', {
headers: {
Authorization: `Bearer ${process.env.WEBRANKPAGE_KEY}`,
},
});
const data = await response.json();
console.log(data);import requests
response = requests.get(
'https://webrankpage.com/api/v1/site-crawls/594/pages',
headers={'Authorization': 'Bearer wrp_live_8fKp2mQx9tR4vN7c'},
)
print(response.json())require 'net/http'
require 'json'
uri = URI('https://webrankpage.com/api/v1/site-crawls/594/pages')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer wrp_live_8fKp2mQx9tR4vN7c'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://webrankpage.com/api/v1/site-crawls/594/pages", nil)
req.Header.Set("Authorization", "Bearer wrp_live_8fKp2mQx9tR4vN7c")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]interface{}
json.NewDecoder(res.Body).Decode(&data)
fmt.Println(data)
}Response
{
"pages": [
{
"id": 12,
"url": "https://onbixo.com/pricing",
"status": 200,
"depth": 1,
"score": 84,
"critical_count": 0
}
],
"total": 90
}GET /site-crawls/{id}/pages/{page_id}
Read one crawled page
The full detail for a single page in the crawl, including its findings.
Request
curl "https://webrankpage.com/api/v1/site-crawls/594/pages/12" \
-H "Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c"<?php
$ch = curl_init('https://webrankpage.com/api/v1/site-crawls/594/pages/12');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c',
],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);// Node 18+, or any server-side runtime. Never in browser code:
// an API key in a page is readable by anyone who opens it.
const response = await fetch('https://webrankpage.com/api/v1/site-crawls/594/pages/12', {
headers: {
Authorization: `Bearer ${process.env.WEBRANKPAGE_KEY}`,
},
});
const data = await response.json();
console.log(data);import requests
response = requests.get(
'https://webrankpage.com/api/v1/site-crawls/594/pages/12',
headers={'Authorization': 'Bearer wrp_live_8fKp2mQx9tR4vN7c'},
)
print(response.json())require 'net/http'
require 'json'
uri = URI('https://webrankpage.com/api/v1/site-crawls/594/pages/12')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer wrp_live_8fKp2mQx9tR4vN7c'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://webrankpage.com/api/v1/site-crawls/594/pages/12", nil)
req.Header.Set("Authorization", "Bearer wrp_live_8fKp2mQx9tR4vN7c")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]interface{}
json.NewDecoder(res.Body).Decode(&data)
fmt.Println(data)
}Response
{
"page": {
"id": 12,
"url": "https://onbixo.com/pricing",
"title": "Pricing",
"score": 84,
"word_count": 812,
"internal_links": 34,
"findings": []
}
}GET /site-crawls/{id}/findings
Findings across the whole crawl
The same issue grouped across every page it affects, which is how you find the template problem rather than the page problem.
Request
curl "https://webrankpage.com/api/v1/site-crawls/594/findings" \
-H "Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c"<?php
$ch = curl_init('https://webrankpage.com/api/v1/site-crawls/594/findings');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer wrp_live_8fKp2mQx9tR4vN7c',
],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);// Node 18+, or any server-side runtime. Never in browser code:
// an API key in a page is readable by anyone who opens it.
const response = await fetch('https://webrankpage.com/api/v1/site-crawls/594/findings', {
headers: {
Authorization: `Bearer ${process.env.WEBRANKPAGE_KEY}`,
},
});
const data = await response.json();
console.log(data);import requests
response = requests.get(
'https://webrankpage.com/api/v1/site-crawls/594/findings',
headers={'Authorization': 'Bearer wrp_live_8fKp2mQx9tR4vN7c'},
)
print(response.json())require 'net/http'
require 'json'
uri = URI('https://webrankpage.com/api/v1/site-crawls/594/findings')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer wrp_live_8fKp2mQx9tR4vN7c'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://webrankpage.com/api/v1/site-crawls/594/findings", nil)
req.Header.Set("Authorization", "Bearer wrp_live_8fKp2mQx9tR4vN7c")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]interface{}
json.NewDecoder(res.Body).Decode(&data)
fmt.Println(data)
}Response
{
"findings": [
{
"check": "media.missing_alt",
"severity": "recommended",
"pages": 46,
"message": "Images without alt text."
}
]
}