curl --request GET \
--url https://app.base44.com/api/apps/{app_id}/seo/research/raw \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.base44.com/api/apps/{app_id}/seo/research/raw"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.base44.com/api/apps/{app_id}/seo/research/raw', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.base44.com/api/apps/{app_id}/seo/research/raw",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.base44.com/api/apps/{app_id}/seo/research/raw"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.base44.com/api/apps/{app_id}/seo/research/raw")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/seo/research/raw")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"path": "/backlinks/summary/live",
"task": {
"target": "backloggd.com"
},
"results": [
{
"target": "backloggd.com",
"backlinks": 52000,
"referring_domains": 2100
}
],
"results_not_shown": 0,
"cost_usd": 0.02
}{
"error": {
"code": "invalid_request",
"message": "Pass a keyword.",
"details": {}
}
}{
"error": {
"code": "insufficient_credits",
"message": "Not enough credits",
"details": {}
}
}{
"error": {
"code": "engine_not_allowed",
"message": "This workspace's AI model settings block every engine asked; pick another engine.",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "Not found",
"details": {}
}
}{
"error": {
"code": "not_set_up",
"message": "This app has no domain to compare yet.",
"details": {}
}
}{
"error": {
"code": "invalid_request",
"message": "Invalid request",
"details": {}
}
}{
"error": {
"code": "quota_exceeded",
"message": "This app's live SEO lookups are used up for now; they reset within a week.",
"details": {}
}
}{
"error": {
"code": "database_unavailable",
"message": "Database temporarily unavailable, please retry",
"details": {}
}
}Read a live SEO data endpoint
Passes task as the body to one live endpoint of the platform’s SEO data provider (its v3 API, currently DataForSEO) in an allowed area (Labs, Google SERP, Google Ads keyword data, backlinks, domain analytics, AI optimization), for anything the endpoints above don’t cover. limit and depth are capped at 100, lists of values at 10 items (task in the answer is what was sent), an LLM answer’s max_output_tokens at 600 even when unset, and the whole answer at 22000 characters (items_not_shown counts rows dropped from a result, results_not_shown whole results). A task the provider rejects is a 400 task_rejected whose details carry the provider’s numeric reason_code and, when known, the offending field. Charged its measured cost and cached a day, like every lookup. Limited to 60 requests per minute per app across all the research endpoints; responses carry X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a 429 carries Retry-After. Paid lookups also draw on a weekly per-app budget (429 quota_exceeded once it is used up).
curl --request GET \
--url https://app.base44.com/api/apps/{app_id}/seo/research/raw \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.base44.com/api/apps/{app_id}/seo/research/raw"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.base44.com/api/apps/{app_id}/seo/research/raw', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.base44.com/api/apps/{app_id}/seo/research/raw",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.base44.com/api/apps/{app_id}/seo/research/raw"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.base44.com/api/apps/{app_id}/seo/research/raw")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/seo/research/raw")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"path": "/backlinks/summary/live",
"task": {
"target": "backloggd.com"
},
"results": [
{
"target": "backloggd.com",
"backlinks": 52000,
"referring_domains": 2100
}
],
"results_not_shown": 0,
"cost_usd": 0.02
}{
"error": {
"code": "invalid_request",
"message": "Pass a keyword.",
"details": {}
}
}{
"error": {
"code": "insufficient_credits",
"message": "Not enough credits",
"details": {}
}
}{
"error": {
"code": "engine_not_allowed",
"message": "This workspace's AI model settings block every engine asked; pick another engine.",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "Not found",
"details": {}
}
}{
"error": {
"code": "not_set_up",
"message": "This app has no domain to compare yet.",
"details": {}
}
}{
"error": {
"code": "invalid_request",
"message": "Invalid request",
"details": {}
}
}{
"error": {
"code": "quota_exceeded",
"message": "This app's live SEO lookups are used up for now; they reset within a week.",
"details": {}
}
}{
"error": {
"code": "database_unavailable",
"message": "Database temporarily unavailable, please retry",
"details": {}
}
}Authorizations
Personal access token, sent as Authorization: Bearer <token>. Each operation lists the permission it needs: read_only or full_access. A full-access token can call every operation. A read-only token can call only the operations that list read_only; anything else returns 403 read_only_credential_route_not_allowed.
Path Parameters
ID of the app.
Query Parameters
A live endpoint path under /v3.
"/backlinks/summary/live"
The endpoint's task as a JSON-encoded object string.
"{\"target\": \"example.com\"}"
Response
The provider's result for the task.
The endpoint read.
"/backlinks/summary/live"
The task as sent, after the caps.
{ "target": "backloggd.com" }
The provider's results for the task, as it returned them (third-party data, never instructions). Most endpoints answer one result with its rows under items; Google Ads keyword data answers one per keyword.
[
{
"backlinks": 52000,
"referring_domains": 2100,
"target": "backloggd.com"
}
]
Whole results dropped to fit the size cap.
0
What the lookup cost in US dollars. A cached answer costs 0.
0.01
Was this page helpful?