Multi-Location Tracking
Track keyword rankings across different countries, states, and cities. Essential for local SEO, international businesses, and location-based services.
Overview
Search results vary significantly by location. A keyword ranking #1 in New York might be on page 3 in Los Angeles. The SerpWatch API lets you specify exact locations to get accurate, location-specific SERP data.
Location Targeting Options
| Parameter | Description | Example |
|---|---|---|
location_name |
Human-readable location name | "New York, United States" |
location_code |
Google Ads location code (numeric) | 1023191 (New York City) |
Location Codes
We recommend using location_code for precise targeting. Location codes
correspond to Google Ads geo targets and provide the most accurate results.
See Locations & Languages for a list of common codes.
Use Cases
- Local SEO - Track rankings in specific cities for local businesses
- Multi-Location Businesses - Monitor performance across franchise locations
- International SEO - Compare rankings across different countries
- Competitor Analysis - See how competitors rank in different markets
- Location-Based Services - Optimize for "near me" and local intent queries
Basic Multi-Location Query
Track the same keyword across multiple locations by submitting separate requests for each location. Use the batch endpoint to submit all locations efficiently.
# Track "pizza delivery" in multiple US cities
curl -X POST "https://engine.v2.serpwatch.io/api/v2/serp/crawl/google/batch" \
-H "Authorization: Bearer $SERPWATCH_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"keyword": "pizza delivery",
"location_name": "New York, United States",
"device": "mobile",
"depth": 20
},
{
"keyword": "pizza delivery",
"location_name": "Los Angeles, United States",
"device": "mobile",
"depth": 20
},
{
"keyword": "pizza delivery",
"location_name": "Chicago, United States",
"device": "mobile",
"depth": 20
}
]'
import requests
import os
API_KEY = os.environ.get("SERPWATCH_API_KEY")
BASE_URL = "https://engine.v2.serpwatch.io"
# Define target locations
locations = [
{"name": "New York, United States", "code": 1023191},
{"name": "Los Angeles, United States", "code": 1013962},
{"name": "Chicago, United States", "code": 1016367},
{"name": "Houston, United States", "code": 1026339},
{"name": "Phoenix, United States", "code": 1013659},
]
keyword = "pizza delivery"
# Build batch request
batch = []
for loc in locations:
batch.append({
"keyword": keyword,
"location_name": loc["name"],
"location_code": loc["code"],
"device": "mobile",
"depth": 20,
"language_code": "en"
})
# Submit batch
response = requests.post(
f"{BASE_URL}/api/v2/serp/crawl/google/batch",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json=batch
)
tasks = response.json()
print(f"Submitted {len(tasks)} location queries")
# Store task IDs for retrieval
task_map = {task["id"]: task["location_name"] for task in tasks}
const API_KEY = process.env.SERPWATCH_API_KEY;
const BASE_URL = "https://engine.v2.serpwatch.io";
// Define target locations
const locations = [
{ name: "New York, United States", code: 1023191 },
{ name: "Los Angeles, United States", code: 1013962 },
{ name: "Chicago, United States", code: 1016367 },
{ name: "Houston, United States", code: 1026339 },
{ name: "Phoenix, United States", code: 1013659 },
];
const keyword = "pizza delivery";
// Build batch request
const batch = locations.map(loc => ({
keyword,
location_name: loc.name,
location_code: loc.code,
device: "mobile",
depth: 20,
language_code: "en"
}));
// Submit batch
const response = await fetch(
`${BASE_URL}/api/v2/serp/crawl/google/batch`,
{
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(batch)
}
);
const tasks = await response.json();
console.log(`Submitted ${tasks.length} location queries`);
// Store task IDs for retrieval
const taskMap = new Map(tasks.map(t => [t.id, t.location_name]));
Common Location Codes
Here are frequently used location codes for the United States. For a complete list, see Locations & Languages.
US Major Cities
| City | Location Code | Location Name |
|---|---|---|
| New York City | 1023191 |
New York, New York, United States |
| Los Angeles | 1013962 |
Los Angeles, California, United States |
| Chicago | 1016367 |
Chicago, Illinois, United States |
| Houston | 1026339 |
Houston, Texas, United States |
| Miami | 1015116 |
Miami, Florida, United States |
| Seattle | 1027744 |
Seattle, Washington, United States |
| Boston | 1018127 |
Boston, Massachusetts, United States |
| San Francisco | 1014221 |
San Francisco, California, United States |
Countries
| Country | Location Code | Language Code |
|---|---|---|
| United States | 2840 |
en |
| United Kingdom | 2826 |
en |
| Canada | 2124 |
en or fr |
| Australia | 2036 |
en |
| Germany | 2276 |
de |
| France | 2250 |
fr |
| Spain | 2724 |
es |
| Brazil | 2076 |
pt |
Complete Multi-Location Workflow
Here's a complete example that tracks keywords across multiple locations and generates a comparison report.
#!/usr/bin/env python3
"""
Multi-Location Rank Tracker
Compares keyword rankings across different geographic locations
"""
import os
import time
import requests
from collections import defaultdict
API_KEY = os.environ.get("SERPWATCH_API_KEY")
BASE_URL = "https://engine.v2.serpwatch.io"
# Configuration
TARGET_DOMAIN = "yourdomain.com"
KEYWORDS = ["pizza delivery", "best pizza near me", "pizza restaurant"]
LOCATIONS = [
{"name": "New York, United States", "code": 1023191},
{"name": "Los Angeles, United States", "code": 1013962},
{"name": "Chicago, United States", "code": 1016367},
]
def submit_batch(keywords, locations):
"""Submit batch request for all keyword/location combinations."""
batch = []
for keyword in keywords:
for location in locations:
batch.append({
"keyword": keyword,
"location_name": location["name"],
"location_code": location["code"],
"device": "mobile",
"depth": 20,
"language_code": "en"
})
response = requests.post(
f"{BASE_URL}/api/v2/serp/crawl/google/batch",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json=batch
)
response.raise_for_status()
return response.json()
def wait_for_results(tasks, timeout=300):
"""Wait for all tasks to complete."""
results = {}
pending = {t["id"] for t in tasks}
start = time.time()
while pending and (time.time() - start) < timeout:
for task_id in list(pending):
response = requests.get(
f"{BASE_URL}/api/v2/serp/crawl/{task_id}",
headers={"Authorization": f"Bearer {API_KEY}"}
)
data = response.json()
if data["status"] in ["success", "completed", "error"]:
results[task_id] = data
pending.remove(task_id)
if pending:
print(f" Waiting... {len(pending)} tasks remaining")
time.sleep(5)
return results
def find_rank(result, domain):
"""Find domain position in organic results."""
for item in result.get("result", {}).get("organic", []):
item_domain = item.get("domain", "").lower()
if domain.lower() in item_domain:
return item["position"]
return None
def generate_report(tasks, results, domain):
"""Generate location comparison report."""
# Organize by keyword -> location -> rank
report = defaultdict(dict)
for task in tasks:
task_id = task["id"]
keyword = task["keyword"]
location = task["location_name"]
result = results.get(task_id, {})
if result.get("status") in ["success", "completed"]:
rank = find_rank(result, domain)
report[keyword][location] = rank
else:
report[keyword][location] = "Error"
return report
def print_report(report, locations):
"""Print formatted comparison report."""
# Header
loc_names = [loc["name"].split(",")[0] for loc in locations]
print("\n" + "=" * 80)
print("MULTI-LOCATION RANKING REPORT")
print("=" * 80)
print(f"\nDomain: {TARGET_DOMAIN}\n")
# Column headers
header = f"{'Keyword':<30}"
for name in loc_names:
header += f"{name:>12}"
print(header)
print("-" * 80)
# Data rows
for keyword, ranks in report.items():
row = f"{keyword[:28]:<30}"
for loc in locations:
rank = ranks.get(loc["name"])
if rank is None:
display = "Not found"
elif rank == "Error":
display = "Error"
else:
display = f"#{rank}"
row += f"{display:>12}"
print(row)
print("-" * 80)
def main():
total_queries = len(KEYWORDS) * len(LOCATIONS)
print(f"Tracking {len(KEYWORDS)} keywords across {len(LOCATIONS)} locations")
print(f"Total queries: {total_queries}")
print("-" * 50)
# Submit batch
print("\nSubmitting batch request...")
tasks = submit_batch(KEYWORDS, LOCATIONS)
print(f"Submitted {len(tasks)} tasks")
# Wait for results
print("\nWaiting for results...")
results = wait_for_results(tasks)
print(f"Received {len(results)} results")
# Generate report
report = generate_report(tasks, results, TARGET_DOMAIN)
print_report(report, LOCATIONS)
if __name__ == "__main__":
main()
Best Practices
Optimize Query Efficiency
- Use batch endpoints - Submit all location queries in a single batch request
- Prioritize locations - Focus on your highest-value markets first
- Set appropriate depth - Use lower depth (10-20) for local tracking where top positions matter most
- Use location codes - More precise than location names and faster to process
Local SEO Considerations
- Mobile-first - Use
device: "mobile"for local searches as most are mobile - Check local pack - Look for your business in the
local_packresults, not just organic - Monitor variations - Track both "pizza delivery" and "pizza delivery near me"
- Track competitors - Include competitor domains in your analysis
Local Pack Results
For local businesses, the local pack (map results) often matters more than organic rankings.
The SERP response includes a local_pack array with map listings. Check both
organic and local pack positions for complete local SEO tracking.
International SEO Tips
- Match language codes - Use the appropriate
language_codefor each country - Account for ccTLDs - Track your country-specific domains (example.de, example.fr)
- Consider hreflang - Different URLs may rank in different countries
- Time zone awareness - Schedule checks at appropriate local times
Credit Usage
Each location query consumes credits separately. Tracking 10 keywords across 5 locations uses 50 credits. Plan your location coverage based on your credit budget and business priorities.