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

> Discover how OpenSEO manages keyword locations for rank tracking. Learn about its use of DataForSEO codes and fallback logic for precise geographic targeting.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: deep-dive
- Published: 2026-09-06

---

**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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/keyword-locations.ts)) converts location codes to lowercase ISO-3166-1 alpha-2 identifiers required by external APIs.

```typescript
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.

```typescript
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

```typescript
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

```typescript
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`](https://github.com/every-app/open-seo/blob/main/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:

```typescript
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`](https://github.com/every-app/open-seo/blob/main/src/shared/rank-tracking.ts). The `estimateScheduledRankCheckCredits()` function (lines 0212–0219) projects usage based on keyword volume, device targeting, result depth, and schedule frequency:

```typescript
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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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.