# How Keyword Location Resolution Handles Different Markets in Open‑SEO

> Learn how Open-SEO's keyword location resolution maps markets and languages to DataForSEO API endpoints, ensuring accurate data across regions with automatic provider selection and fallback mechanisms.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: internals
- Published: 2026-08-18

---

**Open‑SEO maps markets (location + language pairs) to the correct DataForSEO API endpoints through a centralized resolution system that automatically selects providers, validates languages, and gracefully falls back when Labs‑only tools encounter unsupported regions.**

The `every-app/open-seo` repository implements market-aware keyword data fetching in [`src/shared/keyword-locations.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts). This module ensures that every request reaches the right API with a compatible location and language combination, preventing costly failed calls and mismatched search data.

## Core Architecture of Market Resolution

The resolution system rests on three pillars: a canonical location registry, provider-aware routing, and hierarchical override logic.

### The LOCATION_OPTIONS Registry

All supported countries are enumerated in `LOCATION_OPTIONS` ([lines 66‑73](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L66-L73)). Each entry includes:

- `code`: Numeric DataForSEO location identifier
- `label`: Human‑readable country name
- `display_iso`: Short ISO code for UI presentation
- `defaultLanguageCode`: Primary search market language
- `googleAdsOnly`: Optional flag restricting the location to Google Ads API only

This registry is the single source of truth for what markets exist and how they behave.

### Provider Routing with getKeywordDataProvider

Not all locations work with every DataForSEO product. The `getKeywordDataProvider` function ([lines 48‑55](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L48-L55)) inspects the `googleAdsOnly` flag:

```typescript
// Returns "google_ads" for restricted locations, "labs" for standard coverage
const provider = getKeywordDataProvider(locationCode);

```

Labs‑only tools must avoid `googleAdsOnly` markets entirely, which triggers the fallback system described below.

## How resolveMarket Processes Overrides

The `resolveMarket` function ([lines 101‑119](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L101-L119)) implements the core override hierarchy:

1. **Caller‑supplied location** takes precedence over project defaults
2. **Language snaps to location default** when location changes, unless explicitly overridden
3. **Unchanged project defaults** pass through when no overrides provided

```typescript
import { resolveMarket } from "./src/shared/keyword-locations";

const projectDefault = { locationCode: 2840, languageCode: "en" }; // US/English

// Location change triggers language auto‑selection
const germany = resolveMarket({ locationCode: 2276 }, projectDefault);
// → { locationCode: 2276, languageCode: "de" }

// Explicit language override preserved
const vietnam = resolveMarket({ locationCode: 2704, languageCode: "vi" }, projectDefault);
// → { locationCode: 2704, languageCode: "vi" }

```

This prevents the common error of requesting German keywords with English language codes.

## Labs‑Only Tool Handling with resolveLabsMarket

Tools restricted to the DataForSEO Labs API use `resolveLabsMarket` ([lines 145‑159](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L145-L159)), which adds a compatibility check:

```typescript
import { resolveLabsMarket } from "./src/shared/keyword-locations";

// Project based in UAE (googleAdsOnly: true)
const uaeProject = { locationCode: 2784, languageCode: "en" };

const labsCompatible = resolveLabsMarket({}, uaeProject);
// → { locationCode: 2840, languageCode: "en" }  // Falls back to US/EN

```

The function `isLanguageServedForLocation` validates Labs compatibility. When the default market fails this check, `DEFAULT_LOCATION_CODE` (United States, [line 22](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L22)) substitutes with English before delegating to `resolveMarket`.

## Language Validation and Restriction

Two mechanisms prevent invalid language codes from reaching DataForSEO:

**Global validation** via `isSupportedLanguageCode` ([lines 68‑70](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L68-L70)):

```typescript
if (!isSupportedLanguageCode("zz")) {
  throw new Error("Invalid language code: zz");
}

```

**Per‑location restriction** via `getLanguageOptions` ([lines 108‑114](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L108-L114)), which filters the global language list to only those supported for a specific country, including multi‑language overrides defined in `MULTI_LANGUAGE_LOCATIONS`.

## Keyword Data Language Fallback

When SERP and keyword data APIs support different language sets, `resolveKeywordDataLanguage` ([lines 124‑132](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L124-L132)) bridges the gap:

```typescript
// If SERP language "sv" is unsupported for keyword data in target location,
// falls back to location's default language
const dataLanguage = resolveKeywordDataLanguage(requestedLanguage, locationCode);

```

This ensures volume and competition metrics return in a compatible language rather than failing silently.

## Complete Working Example

```typescript
import {
  resolveMarket,
  resolveLabsMarket,
  getKeywordDataProvider,
  getLanguageOptions,
  isSupportedLanguageCode,
} from "./src/shared/keyword-locations";

// Scenario: Multi‑market SEO tool with Labs‑only keyword difficulty feature

const userProject = {
  locationCode: 2840,  // United States
  languageCode: "en"
};

// Standard search request accepts overrides
const searchRequest = resolveMarket(
  { locationCode: 2276 },  // User switches to Germany
  userProject
);
console.log(searchRequest);  // { locationCode: 2276, languageCode: "de" }

// Keyword difficulty tool (Labs‑only) handles unsupported markets
const difficultyRequest = resolveLabsMarket(
  { locationCode: 2784 },  // User requests UAE (googleAdsOnly)
  userProject
);
console.log(difficultyRequest);  // { locationCode: 2840, languageCode: "en" }

// Validate UI input before API call
const userLanguage = "fr";
if (!isSupportedLanguageCode(userLanguage)) {
  console.error("Please select a supported language");
}

// Populate language dropdown for selected country
const availableLanguages = getLanguageOptions(2276);  // Germany
// → [{ code: "de", label: "German" }, { code: "en", label: "English" }, ...]

```

## Key Source Files

| File | Purpose |
|------|---------|
| [[`src/shared/keyword-locations.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts)](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts) | Core implementation including `resolveMarket`, `resolveLabsMarket`, location tables, and provider routing |
| [[`src/shared/keyword-locations.test.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.test.ts)](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.test.ts) | Unit tests for override behavior, fallback logic, and edge cases |
| [[`src/shared/keyword-locations.vendor-defaults.test.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.vendor-defaults.test.ts)](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.vendor-defaults.test.ts) | Validation of DataForSEO Labs default language alignment |

## Summary

- **Market resolution** combines location and language into validated pairs for DataForSEO requests
- **Location overrides** automatically select appropriate default languages unless explicitly specified
- **Labs‑only tools** fall back to US/English when project defaults are Google‑Ads‑only regions
- **Early validation** of language codes prevents charged API failures
- **Per‑location language lists** restrict selections to actually supported combinations

## Frequently Asked Questions

### What happens when a user requests a location that only supports Google Ads?

The `getKeywordDataProvider` function detects the `googleAdsOnly` flag and returns `"google_ads"`. For Labs‑only tools, `resolveLabsMarket` substitutes the fallback location (`DEFAULT_LOCATION_CODE` 2840, United States) with English to ensure the request can proceed.

### How does Open‑SEO prevent language mismatches when switching countries?

The `resolveMarket` function automatically calls `getLanguageCode` to snap the language to the new location's default whenever the location changes. Users must explicitly provide a `languageCode` override to preserve their original selection.

### Why does keyword data sometimes use a different language than SERP data?

DataForSEO's keyword data APIs support fewer languages than their SERP endpoints. The `resolveKeywordDataLanguage` function detects unsupported combinations and falls back to the location's primary language, ensuring volume and competition metrics remain available.

### Where is the master list of supported locations defined?

The `LOCATION_OPTIONS` array in [`src/shared/keyword-locations.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts) ([lines 66‑73](https://github.com/every-app/open-seo/blob/main/src/shared/keyword-locations.ts#L66-L73)) contains all supported countries with their codes, labels, default languages, and Google Ads restrictions.