How OpenSEO Handles Keyword Locations for Rank Tracking: A Technical Deep Dive

OpenSEO uses DataForSEO location codes with fallback logic for languages and API provider selection to ensure every rank-tracking query targets a valid geographic market.

The open-source OpenSEO project (available at every-app/open-seo) implements a robust location-handling system for SERP rank tracking. Its architecture centers on a curated catalog of country codes, intelligent language resolution, and automatic provider routing to DataForSEO's APIs. This ensures that keywords are evaluated in the correct market with appropriate localization settings.

Location Catalog and Data Structure

All supported markets are defined in src/shared/keyword-locations.ts. The static array LOCATION_OPTIONS contains every country available for tracking.

Each location entry includes:

  • location_code – DataForSEO's numeric identifier (e.g., 2840 for United States)
  • label – Human-readable country name
  • short_label – ISO-3166-1 alpha-2 code for display
  • default_language – The market's primary language for fallback purposes
  • googleAdsOnly – Flag indicating Google-Ads-only availability

The United States (2840) serves as the product-wide default, and the list is maintained in alphabetical order for consistent UI rendering.

ISO Code Conversion for API Requests

The getIsoCountryCode() function (lines 0048–0053 in keyword-locations.ts) converts location codes to lowercase ISO-3166-1 alpha-2 identifiers required by external APIs.

import { getIsoCountryCode } from '@/shared/keyword-locations';

// United States
console.log(getIsoCountryCode(2840)); // 'us'

// United Kingdom (special case handling)
console.log(getIsoCountryCode(2826)); // 'gb' (not 'uk')

The function applies a hardcoded override for the United Kingdom to ensure compliance with ISO standards (UK → GB).

Market Resolution with Language Fallback

The resolveMarket() function (lines 0170–0276) merges user-provided location and language preferences with project defaults, applying intelligent fallbacks when inputs are incomplete.

import { resolveMarket } from '@/shared/keyword-locations';

const projectDefaults = { locationCode: 2840, languageCode: 'en' };

// User specifies Canada but omits language
const result = resolveMarket({ locationCode: 2124 }, projectDefaults);

console.log(result);
// { locationCode: 2124, languageCode: 'en' } – inherits Canada's default

This prevents API failures from unsupported language-location combinations while respecting explicit user intent.

Language Validation for Keyword Data Endpoints

DataForSEO's SERP API accepts any language for any location, but its keyword-data endpoints (Labs and Google Ads) enforce stricter validation. The resolveKeywordDataLanguage() function (lines 00831–00840) ensures compatibility:

  • Validates whether the requested language is supported for the given location
  • Falls back to the location's default language when unsupported
  • Returns a guaranteed-valid code for Labs or Google Ads calls
import { resolveKeywordDataLanguage } from '@/shared/keyword-locations';

// Requesting Spanish data for Japan (unsupported combination)
const safeLang = resolveKeywordDataLanguage(2392, 'es');
console.log(safeLang); // 'ja' – falls back to Japan's default

Automatic Provider Selection

The getKeywordDataProvider() function (lines 0055–0062) determines which DataForSEO backend to use based on location availability:

  • "labs" – Used for locations in the Labs catalog (broader metrics support)
  • "google_ads" – Used for Google-Ads-only locations
import { getKeywordDataProvider } from '@/shared/keyword-locations';

console.log(getKeywordDataProvider(2840));    // 'labs' (United States)
console.log(getKeywordDataProvider(2344));    // 'google_ads' (Hong Kong)

This routing happens automatically without user intervention.

SERP Request Construction in Rank Tracking

When src/shared/rank-tracking.ts schedules a rank check, it packages resolved location and language values into the DataForSEO payload. The implementation separates concerns between SERP and keyword-data requirements:

import { 
  getKeywordDataProvider, 
  resolveKeywordDataLanguage 
} from '@/shared/keyword-locations';

function buildSerpPayload(locationCode: number, languageCode: string) {
  return {
    location_code: locationCode,
    language_code: languageCode,                    // SERP: any language accepted
    keyword_language: resolveKeywordDataLanguage(locationCode, languageCode),
    provider: getKeywordDataProvider(locationCode),
  };
}

// Hong Kong with English preference
const payload = buildSerpPayload(2344, 'en');
/*
{
  location_code: 2344,
  language_code: 'en',
  keyword_language: 'en',      // validated as supported
  provider: 'google_ads'
}
*/

Input Validation Guards

Multiple guard functions prevent invalid API calls:

Function Purpose Line Range
isSupportedLocationCode() Verifies location exists in catalog
isLabsLocationCode() Checks Labs availability
isLanguageServedForLocation() Validates language-location compatibility

These run before any external request, catching errors early in the pipeline.

Cost Estimation Integration

The location system integrates with cost calculation in src/shared/rank-tracking.ts. The estimateScheduledRankCheckCredits() function (lines 0212–0219) projects usage based on keyword volume, device targeting, result depth, and schedule frequency:

import { estimateScheduledRankCheckCredits } from '@/shared/rank-tracking';

const estimate = estimateScheduledRankCheckCredits(
  20,        // keywords
  'both',    // desktop + mobile
  30,        // results depth
  'weekly',  // schedule
);

console.log(estimate.monthlyCostUsd);    // 0.048
console.log(estimate.monthlyCostCredits); // 48

Server-Side Execution Flow

The server endpoint at src/serverFunctions/rank-tracking.ts receives client requests and orchestrates the full pipeline:

  1. Receives location and language parameters
  2. Calls resolveMarket() to normalize inputs
  3. Validates with guard functions
  4. Constructs DataForSEO payload with resolved values
  5. Dispatches to appropriate API endpoint

This ensures consistent behavior across all rank-tracking operations.

Summary

  • Static catalog in keyword-locations.ts defines all supported markets with metadata
  • ISO conversion handles edge cases like United Kingdom (UK → GB)
  • Language resolution provides sensible fallbacks for incomplete or invalid combinations
  • Provider routing automatically selects Labs or Google Ads based on location type
  • Validation guards prevent API errors before requests are sent
  • Server integration combines all components for reliable rank-tracking execution

Frequently Asked Questions

What happens if I specify a language that isn't supported for my chosen location?

The system falls back to the location's default language. For example, requesting Spanish (es) for Japan (2392) automatically switches to Japanese (ja). This fallback is handled by resolveKeywordDataLanguage() in keyword-locations.ts, ensuring API requests always succeed.

Can I track rankings for Google-Ads-only locations like Hong Kong?

Yes. Locations flagged with googleAdsOnly: true route automatically to the Google Ads API via getKeywordDataProvider(). You don't need to configure this manually—the system detects the location code and selects the appropriate backend.

Why does the United Kingdom convert to 'gb' instead of 'uk'?

The getIsoCountryCode() function applies a hardcoded override (UK → GB) to comply with ISO-3166-1 alpha-2 standards. While DataForSEO accepts various identifiers, external APIs and data processors typically require strict ISO compliance, making this conversion necessary for reliable integrations.

How does OpenSEO estimate costs for scheduled rank checks?

The estimateScheduledRankCheckCredits() function in rank-tracking.ts calculates credits based on four factors: number of keywords, device targeting (desktop/mobile/both), SERP result depth, and schedule frequency. It returns per-run costs, monthly projections, and credit consumption for budget planning.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →