# Routing Logic for the Google Ads Keyword-Data Provider in googleAdsOnly Countries

> Understand the routing logic for the Google Ads keyword-data provider in googleAdsOnly countries. Learn how it validates ISO country codes and invokes the Google Ads API, rejecting unsupported regions.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-09-04

---

**The Google Ads keyword-data provider in the every-app/open-seo repository routes requests through a dedicated API endpoint that validates ISO country codes against a strict whitelist before invoking the Google Ads API, rejecting unsupported regions with a 400 Bad Request response.**

The `every-app/open-seo` project implements a secure, country-restricted routing layer for its Google Ads keyword research functionality. This routing logic ensures that keyword data queries are processed only for predefined geographic markets, preventing unauthorized access to unsupported regions while maintaining clean separation between route handling and external API integration.

## API Endpoint and Route Structure

The keyword-data service exposes a dedicated route that handles country-specific filtering through query parameters.

### Route Registration

The server-side routing tree is auto-generated in [`web/src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/web/src/routeTree.gen.ts). This file registers the marketing section route that maps HTTP requests to the concrete handler:

```typescript
{
  id: '/marketing/google-ads/keyword-data',
  path: '/marketing/google-ads/keyword-data',
  //…other route metadata
}

```

Incoming GET requests to `/api/google-ads/keyword-data` are matched against this entry and forwarded to [`web/src/routes/_marketing/google-ads/keyword-data.ts`](https://github.com/every-app/open-seo/blob/main/web/src/routes/_marketing/google-ads/keyword-data.ts).

### Request Handling

The handler expects a `countries` query parameter containing comma-separated ISO-3166-1 alpha-2 codes. The router extracts these values and initiates the validation pipeline before any external API calls occur.

## Country Validation Workflow

The routing logic enforces geographic restrictions through a whitelist check defined in [`src/lib/googleAds/countries.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/googleAds/countries.ts).

The `SUPPORTED_COUNTRIES` Set contains the allowed region codes:

```typescript
const SUPPORTED_COUNTRIES = new Set([
  'US', 'CA', 'GB', 'AU', 'DE', 'FR', 'JP', 'BR', // …etc.
]);

```

Inside the route handler, the validation logic parses and verifies the input:

```typescript
const url = new URL(request.url);
const raw = url.searchParams.get('countries') ?? '';
const countries = raw.split(',').map(c => c.trim().toUpperCase());

if (!countries.length || !countries.every(c => SUPPORTED_COUNTRIES.has(c))) {
  return new Response('Invalid or unsupported country codes', { status: 400 });
}

```

Any request containing country codes outside this whitelist immediately receives a **400 Bad Request** response, preventing unauthorized or accidental queries for unsupported regions.

## Provider Invocation

After successful validation, the handler instantiates the `GoogleAdsKeywordDataProvider` class from [`src/lib/googleAds/KeywordDataProvider.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/googleAds/KeywordDataProvider.ts) and invokes its `getKeywords` method:

```typescript
const provider = new GoogleAdsKeywordDataProvider();
const result = await provider.getKeywords({ countries });

```

The provider constructs a Google Ads API request that includes a `LocationSearchParameter` for every validated country code, ensuring keyword suggestions, search volume estimates, and competition metrics reflect only the specified geographic markets.

The final response returns the provider's JSON payload with a **200 OK** status:

```typescript
return new Response(JSON.stringify(result), {
  headers: { 'Content-Type': 'application/json' },
  status: 200,
});

```

### Client Integration Example

Applications consume this endpoint by passing the required country parameter:

```typescript
fetch(
  '/api/google-ads/keyword-data?countries=US,CA,GB',
  { method: 'GET' }
)
  .then(r => r.ok ? r.json() : Promise.reject(r.status))
  .then(data => console.log('Keyword data:', data))
  .catch(err => console.error('Request failed:', err));

```

## Summary

- The `/api/google-ads/keyword-data` route accepts GET requests with a mandatory `countries` query parameter containing comma-separated ISO-3166-1 alpha-2 codes.
- The handler in [`web/src/routes/_marketing/google-ads/keyword-data.ts`](https://github.com/every-app/open-seo/blob/main/web/src/routes/_marketing/google-ads/keyword-data.ts) validates all country codes against the `SUPPORTED_COUNTRIES` whitelist defined in [`src/lib/googleAds/countries.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/googleAds/countries.ts).
- Requests containing unsupported codes receive an immediate **400 Bad Request** without invoking the external API.
- Valid requests instantiate `GoogleAdsKeywordDataProvider` and call `getKeywords()`, which builds location-specific API calls using `LocationSearchParameter` instances.
- This whitelist approach ensures keyword data is only retrieved for explicitly permitted regions, controlling API costs and ensuring data compliance.

## Frequently Asked Questions

### What happens if I request keyword data for an unsupported country?

The route handler checks every submitted country code against the `SUPPORTED_COUNTRIES` Set in [`src/lib/googleAds/countries.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/googleAds/countries.ts). If any code is missing from the whitelist, the handler returns a **400 Bad Request** response with the message "Invalid or unsupported country codes" and never calls the Google Ads API.

### Where is the country whitelist defined in the codebase?

The whitelist is exported from [`src/lib/googleAds/countries.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/googleAds/countries.ts) as a constant Set named `SUPPORTED_COUNTRIES`. This file contains the complete list of ISO-3166-1 alpha-2 codes that the keyword-data provider is authorized to query.

### How does the provider handle multiple countries in a single request?

The `GoogleAdsKeywordDataProvider` class accepts an array of country codes and constructs a Google Ads API request that includes a separate `LocationSearchParameter` for each country. This generates keyword ideas and metrics aggregated across all specified locations while maintaining the restriction to whitelisted regions only.

### Is the route path configurable or auto-generated?

The route path is defined in the auto-generated file [`web/src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/web/src/routeTree.gen.ts), which maps `/marketing/google-ads/keyword-data` to the handler at [`web/src/routes/_marketing/google-ads/keyword-data.ts`](https://github.com/every-app/open-seo/blob/main/web/src/routes/_marketing/google-ads/keyword-data.ts). While the underlying framework supports route configuration, the actual path structure follows the file-based routing convention used throughout the project.