Count which selected keywords a bulk action applies to
curl --request POST \
--url https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"selection": {
"mode": "ids",
"ids": [
"<string>"
]
},
"teamId": "<string>"
}
'import requests
url = "https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview"
payload = {
"selection": {
"mode": "ids",
"ids": ["<string>"]
},
"teamId": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({selection: {mode: 'ids', ids: ['<string>']}, teamId: '<string>'})
};
fetch('https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview', 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://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'selection' => [
'mode' => 'ids',
'ids' => [
'<string>'
]
],
'teamId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview"
payload := strings.NewReader("{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"eligibility": {
"selected": 123,
"eligible": 123,
"skipped": 123,
"byReason": {}
}
}{
"success": true,
"error": "<string>",
"code": "<string>",
"message": "<string>",
"reference": "<string>"
}Rank Tracking
Bulk keyword actions
Preview, track, untrack, or delete many tracked keywords at once.
POST
/
v3
/
rank-tracking
/
keywords
/
bulk-preview
Count which selected keywords a bulk action applies to
curl --request POST \
--url https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"selection": {
"mode": "ids",
"ids": [
"<string>"
]
},
"teamId": "<string>"
}
'import requests
url = "https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview"
payload = {
"selection": {
"mode": "ids",
"ids": ["<string>"]
},
"teamId": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({selection: {mode: 'ids', ids: ['<string>']}, teamId: '<string>'})
};
fetch('https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview', 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://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'selection' => [
'mode' => 'ids',
'ids' => [
'<string>'
]
],
'teamId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview"
payload := strings.NewReader("{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/rank-tracking/keywords/bulk-preview")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"eligibility": {
"selected": 123,
"eligible": 123,
"skipped": 123,
"byReason": {}
}
}{
"success": true,
"error": "<string>",
"code": "<string>",
"message": "<string>",
"reference": "<string>"
}Every bulk action takes a
Each call processes one batch of eligible keywords and returns
selection and works through it in batches:
selectionis either{ mode: "ids", ids: [trackedKeywordId, ...] }or{ mode: "all", filters: { search?, country? }, excludedIds: [...] }(every keyword matching the filters, minus the excluded ids).- Call
POST /v3/rank-tracking/keywords/bulk-previewwith theselectionand anaction(track,untrackordelete) first. It changes nothing and returnseligibility:{ selected, eligible, skipped, byReason }, e.g. keywords skipped because they are already tracked or being refreshed.
| Action | Endpoint | Rows per call | Notes |
|---|---|---|---|
| Track | POST /v3/rank-tracking/keywords/bulk-track | 50 | Resumes tracking for saved, untracked keywords. Uses the keyword-tracking allowance; 402 at the limit. |
| Untrack | POST /v3/rank-tracking/keywords/bulk-untrack | 50 | Soft untrack: history is kept and the allowance is refunded. |
| Delete | POST /v3/rank-tracking/keywords/bulk-delete | 50 | Permanent. Removes rank history; topic membership is kept. |
{ success, succeeded, failed, nextCursor, eligibility, results }. While nextCursor is not null, call again with the same selection and afterId set to nextCursor. results has one entry per keyword with id, keyword, success and error when it failed.
A call returns 409 if a selected keyword started refreshing mid-batch.
To add new keywords by text, use Add Tracked Keyword. To change one keyword, including its active state, use PATCH /v3/rank-tracking/keywords/{id}.Authorizations
bearerAuthapiKey
Your SnowSEO API key (sk_...).
Body
application/json
Response
Default Response
Show child attributes
Show child attributes
Was this page helpful?

