Providers

Rankings, web search, Search Console and the language model, and how to add your own.

All external services are swappable seams. Pick per deployment in seo.config.json (providers.*) and set the matching keys in Vault. Every provider is fail-soft — on any error it returns an empty result rather than throwing, so one flaky dependency never crashes a run.

SERP (rankings) — providers.serp

Reads the public search ranking for a keyword. search(query, opts?) → { results: {url,title}[] }.

ValueImplKeysNotes
google (default)googleProvider({ apiKey, cx })GOOGLE_SEARCH_API_KEY, GOOGLE_SEARCH_CXNeeds a GCP project with Custom Search API enabled.
serperserperProvider({ apiKey })SERPER_API_KEYSingle key, no GCP setup. Serves SERP + web search.
fakefakeProvider(fixture)—Tests only.

Web search (competitor discovery) — providers.webSearch

Used by the competitor researcher to find a competitor's pages. Same search() shape. google uses googleWebSearch({ apiKey, cx }); serper reuses serperProvider.

Search Console (optional) — providers.searchConsole

Owner-measured positions/impressions, higher fidelity than public SERP. Off by default (null). gscProvider({ token, siteUrl, days?, rowLimit? }) → positions() → {keyword,position,impressions}[]. Requires an OAuth token for a property you own (GSC_OAUTH_TOKEN).

LLM (analysis + proposals)

Anthropic via callClaude({ system, user }). The reference uses claude-haiku-4-5 for cost. Key: ANTHROPIC_API_KEY. Untrusted fetched content is always fenced in <data> tags and the fences are neutralized in the input (see docs/SECURITY.md).

Adding a provider

Implement the interface (adapter/serpProvider.d.ts or searchConsole.d.ts), keep it fail-soft, inject fetchImpl for tests, add a fake + test, then reference it from the edge shell. No core changes required.