Lemon AI Web Search Provider Implementations: Available Backends and Configuration Guide
Lemon AI supports seven distinct web search provider implementations—including Tavily, Google Custom Search, Cloudsway, Metaso, local Bing/Baidu scraping, and an internal Lemon search—each configurable via database records in SearchProvider and UserProviderConfig or environment variables for Google.
Lemon AI provides a modular WebSearch tool that routes queries to multiple third-party search backends through a unified interface. According to the hexdocom/lemonai source code, the system implements a pluggable architecture where each provider resides in src/tools/impl/web_search/ and is wired into the generic tool through src/tools/WebSearch.js. This guide details the available web search provider implementations and their configuration methods.
Available Web Search Provider Implementations in Lemon AI
Each provider is implemented as a separate class under src/tools/impl/web_search/ and exposes a standard interface: search(query, options), formatContent(), formatJSON(), and check().
Tavily Search Provider
The Tavily implementation resides in src/tools/impl/web_search/TalivySearch.js. This provider calls the public Tavily HTTP API using bearer token authentication (Authorization: Bearer <api_key>).
Configuration requires an api_key string stored in the base_config field of the UserProviderConfig table:
await UserProviderConfig.create({
user_id: userId,
provider_id: tavilyProviderId,
base_config: { api_key: 'tvly-xxxxxxxxxxxxxxxxxxxxxxxxxx' }
})
Google Custom Search Provider
The Google Custom Search implementation is located in src/tools/impl/web_search/GoogleSearch.js with a standalone runner at src/tools/impl/web_search/GoogleSearch.run.js. This provider uses the official googleapis client to interact with the Google Custom Search Engine (CSE) API.
Unlike other providers, Google Custom Search relies on environment variables rather than database configuration:
// src/tools/impl/web_search/GoogleSearch.run.js
const tool = new GoogleSearch({
key: process.env.GOOGLE_API_KEY,
cx: process.env.GOOGLE_SEARCH_ENGINE_ID
})
Set GOOGLE_API_KEY and GOOGLE_SEARCH_ENGINE_ID in your runtime environment (e.g., .env file or Docker compose configuration).
Cloudsway Search Provider
The Cloudsway provider in src/tools/impl/web_search/CloudswaySearch.js sends GET requests to https://searchapi.cloudsway.net/search/{endpoint}/base with bearer token authentication.
Configuration requires both an api_key (access key) and an endpoint string:
await UserProviderConfig.create({
user_id: userId,
provider_id: cloudswayProviderId,
base_config: {
api_key: 'your-access-key',
endpoint: 'your-endpoint-name'
}
})
Metaso Search Provider
The Metaso implementation in src/tools/impl/web_search/MetasoSearch.js POSTs JSON payloads to <endpoint>/search using bearer token authentication.
Configuration follows the same pattern as Cloudsway, requiring api_key and endpoint in UserProviderConfig.base_config:
await UserProviderConfig.upsert({
user_id: userId,
provider_id: metasoProviderId,
base_config: {
api_key: 'your-metaso-key',
endpoint: 'https://api.metaso.io'
}
})
Local Bing/Baidu Search Provider
The Local provider in src/tools/impl/web_search/LocalSearch.js launches a headless Chromium instance via Playwright to scrape public Bing or Baidu SERP pages. This provider requires no API keys or database configuration.
Selection of the search engine (bing or baidu) occurs at runtime through the engine parameter:
// Inside WebSearch.js switch case
case 'Baidu':
obj = await doLocalSearch(query, options, 'baidu');
break;
case 'Bing':
obj = await doLocalSearch(query, options, 'bing');
break;
Lemon Internal Search Provider
The Lemon internal provider is invoked via doLemonSearch in src/tools/WebSearch.js. This implementation sends queries to Lemon's sub-server endpoint (/api/sub_server/search) and is entirely internal, requiring no user-provided API keys or configuration.
Configuring Web Search Providers in Lemon AI
Lemon AI uses a three-tier configuration system involving global provider definitions, user-specific credentials, and runtime environment variables.
Database Schema and Default Definitions
Global provider definitions are seeded from public/default_data/default_search_provider.json. This JSON file defines the base_config_schema for each provider:
{
"name": "Metaso",
"logo_url": "...",
"base_config_schema": {
"api_key": "",
"endpoint": ""
}
}
These definitions populate the SearchProvider table (src/models/SearchProvider.js), which stores the JSON schema and metadata.
User-specific configurations reside in UserProviderConfig (src/models/UserProviderConfig.js), linking users to providers via foreign keys and storing encrypted credentials in base_config.
Runtime Provider Selection
The active provider for a session is determined by the UserSearchSetting table (src/models/UserSearchSetting.js), which references provider_id and optional result_count. The WebSearch tool queries this setting on each execution:
const searchProvider = await SearchProvider.findOne({
where: { id: userSearchSetting.provider_id }
})
Environment Variable Configuration
For Google Custom Search, credentials bypass the database and are read directly from the environment in src/tools/impl/web_search/GoogleSearch.run.js:
export GOOGLE_API_KEY="your-api-key"
export GOOGLE_SEARCH_ENGINE_ID="your-cx-id"
Practical Implementation Examples
Switching Providers Programmatically
To activate Metaso for a specific user:
const { UserProviderConfig, UserSearchSetting } = require('@src/models')
// Store credentials
await UserProviderConfig.upsert({
user_id: userId,
provider_id: metasoProviderId,
base_config: {
api_key: 'YOUR_METASO_KEY',
endpoint: 'https://api.metaso.io'
}
})
// Set as active provider
await UserSearchSetting.update(
{ provider_id: metasoProviderId },
{ where: { user_id: userId } }
)
Executing a Web Search
Using the generic WebSearch tool:
const WebSearchTool = require('@src/tools/WebSearch')
const result = await WebSearchTool.execute({
query: 'latest AI breakthroughs',
num_results: 5,
conversation_id: 'abc123' // Required only for Lemon internal search
})
console.log(result.content) // Human-readable formatted results
console.log(result.meta.json) // Structured JSON payload
Performing Provider Health Checks
Verify API connectivity before production deployment:
const MetasoSearch = require('@src/tools/impl/web_search/MetasoSearch')
const meta = new MetasoSearch({
key: 'YOUR_KEY',
endpoint: 'https://api.metaso.io'
})
const status = await meta.check()
console.log(status)
// Output: { status: 'success', message: 'Metaso Search API connection successful.' }
Summary
- Lemon AI provides seven web search provider implementations: Tavily, Google Custom Search, Cloudsway, Metaso, Local (Bing/Baidu scraper), and an internal Lemon search.
- Provider classes reside in
src/tools/impl/web_search/and expose standardized methods:search(),formatContent(),formatJSON(), andcheck(). - Configuration is tiered: Global schemas live in
public/default_data/default_search_provider.jsonand theSearchProvidertable; user credentials store inUserProviderConfig; active selection happens viaUserSearchSetting. - Google Custom Search uniquely uses environment variables (
GOOGLE_API_KEY,GOOGLE_SEARCH_ENGINE_ID) rather than database storage. - Local search requires no API keys, utilizing Playwright to scrape Bing or Baidu directly.
Frequently Asked Questions
How do I add a new web search provider to Lemon AI?
Implement a new class in src/tools/impl/web_search/ that exposes search(query, options), formatContent(), formatJSON(), and check() methods following the existing provider pattern. Register the provider by adding a JSON definition to public/default_data/default_search_provider.json with the appropriate base_config_schema, then seed the SearchProvider table. Users can then store credentials via UserProviderConfig and activate the provider through UserSearchSetting.
Why does the Google provider use environment variables instead of database configuration?
The Google Custom Search implementation in src/tools/impl/web_search/GoogleSearch.run.js reads GOOGLE_API_KEY and GOOGLE_SEARCH_ENGINE_ID from process.env rather than the database. This design allows developers to run the Google search runner as a standalone script without database connectivity, simplifying local development and serverless deployments. For production integration, ensure these variables are set in your runtime environment or Docker configuration.
Can I use the Local search provider for production workloads?
The Local provider in src/tools/impl/web_search/LocalSearch.js uses Playwright to launch headless Chromium instances and scrape Bing or Baidu SERP pages. While this requires no API keys and avoids rate limits associated with commercial APIs, it is computationally expensive and slower than API-based providers. It is best suited for fallback scenarios, development environments, or regions where commercial APIs are unavailable. For high-throughput production use, API-based providers like Tavily or Google Custom Search are recommended.
How do I verify that my provider configuration is working correctly?
Each provider class implements a check() method that performs a health check against the respective API endpoint. Instantiate the provider class directly with your configuration and call check():
const CloudswaySearch = require('@src/tools/impl/web_search/CloudswaySearch');
const provider = new CloudswaySearch({
key: 'your-key',
endpoint: 'your-endpoint'
});
const status = await provider.check();
console.log(status); // { status: 'success', message: '...' }
For database-configured providers, ensure the UserProviderConfig row contains valid base_config JSON matching the schema defined in SearchProvider.base_config_schema.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →