curl --request GET \
--url https://app.base44.com/api/apps/{app_id}/seo/research/search-performance \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.base44.com/api/apps/{app_id}/seo/research/search-performance"
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/search-performance', 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/search-performance",
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/search-performance"
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/search-performance")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/seo/research/search-performance")
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{
"source": "search_console",
"days": 28,
"totals": {
"clicks": 120,
"impressions": 4300,
"ctr": 0.028,
"position": 14.2
},
"previous_totals": {
"clicks": 98,
"impressions": 3900,
"ctr": 0.025,
"position": 15.1
},
"top_queries": [
{
"query": "game tracker",
"clicks": 30
}
],
"top_pages": [
{
"page": "/",
"clicks": 70
}
]
}{
"error": {
"code": "invalid_request",
"message": "Pass a keyword.",
"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": "unavailable",
"message": "Live SEO data is unavailable right now.",
"details": {}
}
}Get search performance
Google clicks, impressions, CTR, position, top queries and pages from Search Console, or estimated rankings when Search Console isn’t connected. Limited to 60 requests per minute per app across all six 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/search-performance \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.base44.com/api/apps/{app_id}/seo/research/search-performance"
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/search-performance', 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/search-performance",
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/search-performance"
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/search-performance")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/seo/research/search-performance")
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{
"source": "search_console",
"days": 28,
"totals": {
"clicks": 120,
"impressions": 4300,
"ctr": 0.028,
"position": 14.2
},
"previous_totals": {
"clicks": 98,
"impressions": 3900,
"ctr": 0.025,
"position": 15.1
},
"top_queries": [
{
"query": "game tracker",
"clicks": 30
}
],
"top_pages": [
{
"page": "/",
"clicks": 70
}
]
}{
"error": {
"code": "invalid_request",
"message": "Pass a keyword.",
"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": "unavailable",
"message": "Live SEO data is unavailable right now.",
"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
Window in days, one of [7, 28, 90]. Default 28.
Response
Search Console numbers, or estimated rankings (source: "estimated_rankings").
Was this page helpful?