# Lemon AI Web Search Provider Implementations: Available Backends and Configuration Guide

> Discover Lemon AI's web search provider options including Tavily, Google, and more. Configure them easily via database or environment variables for efficient searching.

- Repository: [hexdocom/lemonai](https://github.com/hexdocom/lemonai)
- Tags: how-to-guide
- Published: 2026-03-03

---

**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`](https://github.com/hexdocom/lemonai/blob/main/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`](https://github.com/hexdocom/lemonai/blob/main/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:

```javascript
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`](https://github.com/hexdocom/lemonai/blob/main/src/tools/impl/web_search/GoogleSearch.js) with a standalone runner at [`src/tools/impl/web_search/GoogleSearch.run.js`](https://github.com/hexdocom/lemonai/blob/main/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:

```javascript
// 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`](https://github.com/hexdocom/lemonai/blob/main/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:

```javascript
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`](https://github.com/hexdocom/lemonai/blob/main/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`:

```javascript
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`](https://github.com/hexdocom/lemonai/blob/main/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:

```javascript
// 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`](https://github.com/hexdocom/lemonai/blob/main/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`](https://github.com/hexdocom/lemonai/blob/main/public/default_data/default_search_provider.json). This JSON file defines the `base_config_schema` for each provider:

```json
{
  "name": "Metaso",
  "logo_url": "...",
  "base_config_schema": {
    "api_key": "",
    "endpoint": ""
  }
}

```

These definitions populate the **`SearchProvider`** table ([`src/models/SearchProvider.js`](https://github.com/hexdocom/lemonai/blob/main/src/models/SearchProvider.js)), which stores the JSON schema and metadata.

User-specific configurations reside in **`UserProviderConfig`** ([`src/models/UserProviderConfig.js`](https://github.com/hexdocom/lemonai/blob/main/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`](https://github.com/hexdocom/lemonai/blob/main/src/models/UserSearchSetting.js)), which references `provider_id` and optional `result_count`. The `WebSearch` tool queries this setting on each execution:

```javascript
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`](https://github.com/hexdocom/lemonai/blob/main/src/tools/impl/web_search/GoogleSearch.run.js):

```bash
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:

```javascript
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:

```javascript
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:

```javascript
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()`, and `check()`.
- **Configuration is tiered**: Global schemas live in [`public/default_data/default_search_provider.json`](https://github.com/hexdocom/lemonai/blob/main/public/default_data/default_search_provider.json) and the `SearchProvider` table; user credentials store in `UserProviderConfig`; active selection happens via `UserSearchSetting`.
- **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`](https://github.com/hexdocom/lemonai/blob/main/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`](https://github.com/hexdocom/lemonai/blob/main/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`](https://github.com/hexdocom/lemonai/blob/main/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()`:

```javascript
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`.