OpenSEO's keyword research system uses a thin service facade (KeywordResearchService.ts) that orchestrates research, SERP analysis, and saved-keyword management, with all server functions protected by project-context middleware and normalized with project market settings before execution. Keyword data sourcing is abstracted by location—resolved at runtime via getKeywordDataProvider(locationCode)—while e2e tests can override live calls with fixtures when VITE_E2E_KEYWORD_FIXTURES=1.
KeywordResearchService.ts at src/server/features/keywords/services/KeywordResearchService.ts is a thin re-export facade: it assembles the KeywordResearchService object by collecting individual functions (research, getSerpAnalysis, saveKeywords, getSavedKeywords, exportSavedKeywords, updateSavedKeywordTags, updateSavedKeywordTag, deleteSavedKeywordTag, removeSavedKeywords, refreshSavedKeywordMetrics) from src/server/features/keywords/services/research.[1]
All keyword server functions in src/serverFunctions/keywords.ts use the requireProjectContext middleware, which gates access to a project and supplies context.projectId and context.project before any handler runs.[2] The researchKeywords server function in src/serverFunctions/keywords.ts merges resolveMarket(data, context.project) into the input before calling KeywordResearchService.research, normalising locale and market fields from the project settings when the caller omits them.[2] When VITE_E2E_KEYWORD_FIXTURES=1, the researchKeywords server function short-circuits to return fixture data from e2e/fixtures/keyword-research-fixtures instead of calling the live KeywordResearchService.[2]
Keyword data provider is resolved by getKeywordDataProvider(locationCode), defaulting to Labs with Google-Ads-only fallback for unsupported countries
getKeywordDataProvider(locationCode)
Sources