Multi-Engine SERP API for Agents - Brave, DuckDuckGo, Mojeek avatar

Multi-Engine SERP API for Agents - Brave, DuckDuckGo, Mojeek

Pricing

from $0.00005 / actor start

Go to Apify Store
Multi-Engine SERP API for Agents - Brave, DuckDuckGo, Mojeek

Multi-Engine SERP API for Agents - Brave, DuckDuckGo, Mojeek

One normalized search API across Brave, DuckDuckGo and Mojeek. Uniform JSON schema, BYO API keys, per-query pay-per-event pricing, and low-latency Standby HTTP mode for AI agents.

Pricing

from $0.00005 / actor start

Rating

0.0

(0)

Developer

Eonix Pvt Ltd

Eonix Pvt Ltd

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

3 days ago

Last modified

Share

Multi-Engine SERP API for Agents — Brave, DuckDuckGo, Mojeek

One search call, three engines, one schema. serp-multi gives AI agents (and the humans building them) a normalized web-search API across Brave, DuckDuckGo, and Mojeek — with predictable per-query pricing, bring-your-own API keys, cross-engine deduplication, optional LLM re-ranking, and a low-latency Standby HTTP endpoint so your agent gets an answer in one round-trip instead of waiting for a batch run.

Built for agent consumption first:

  • Uniform JSON schema — every engine's results come back as the same record shape. Your agent parses one format, forever.
  • Predictable cost — pay-per-event: a flat price per query × engine executed. No token surprises, no per-GB ambiguity. Failed engine calls are never charged.
  • Real-time via Standby modeGET /search?q=… returns JSON in the response body with cold-start-free latency. Perfect as an agent tool or an MCP tool.
  • BYO keys where engines have official APIs — Brave and Mojeek run through their official APIs with your keys (both have free tiers), so you control quotas and stay in each engine's terms. DuckDuckGo needs no key.
  • Cross-engine consensus — results pointing at the same canonical URL are merged, keeping each engine's rank in enginesRanks. Agreement across independent indexes is a strong relevance signal.

Supported engines

EngineHowKey needed?Notes
braveOfficial Brave Search APIYes — braveApiKey (free tier: 2,000 queries/mo)Skipped with a logged warning if no key
duckduckgoHTML endpoint via got-scraping + CheerioNoGraceful degradation on blocks: one proxy retry, then partial results with a warning
mojeekOfficial Mojeek Search APIYes — mojeekApiKeyIndependent index — great diversity signal. Skipped if no key

Quick start (batch mode)

Run the Actor with:

{
"queries": ["apify actor pricing", "best vector database"],
"engines": ["brave", "duckduckgo", "mojeek"],
"resultsPerEngine": 10,
"mergeResults": true,
"braveApiKey": "YOUR_BRAVE_KEY",
"mojeekApiKey": "YOUR_MOJEEK_KEY"
}

Every query is searched on every enabled engine (concurrency-limited, retried with exponential backoff, 429 Retry-After respected) and normalized records land in the default dataset.

Standby mode — the real-time agent endpoint

This Actor supports Apify Actor Standby: the platform keeps a warm instance running an HTTP server, so requests answer in real time.

GET https://<your-username>--serp-multi.apify.actor/search?q=best+vector+database&engines=duckduckgo,brave
Authorization: Bearer <YOUR_APIFY_TOKEN>

Query parameters (all optional except q):

ParamMeaningDefault
qThe search query (required)
enginesComma-separated subset of brave,duckduckgo,mojeekrun input / all
resultsPerEngine (alias count)1–50 results per enginerun input / 10
country, languageTwo-letter localization codesus, en
mergeResults (alias merge)true/false cross-engine mergetrue
reranktrue to LLM-rerank (needs openaiApiKey in the standby run input)false

Secrets never travel in the URL. API keys (braveApiKey, mojeekApiKey, openaiApiKey) are configured once in the standby run's input; per-request params only tune non-secret options.

The endpoint returns the same normalized records as batch mode, in a JSON envelope:

{ "query": "…", "count": 12, "results": [], "engines": { "executed": ["brave"], "skipped": [], "failed": [] }, "reranked": false, "warnings": [], "latencyMs": 913 }

Standby requests charge the same pay-per-event prices as batch runs — one serp-query event per engine executed.

Use as an MCP tool

Apify exposes every Actor as an MCP (Model Context Protocol) tool — no extra code in this Actor needed. Point your MCP client (Claude, or any MCP-capable agent framework) at the Apify MCP server, allow serp-multi, and your agent can call multi-engine search natively as a tool. Combined with Standby mode, that gives your agent sub-second, fixed-price web search.

Input reference

FieldTypeDefaultDescription
queriesstring[]Search queries. Required in batch mode; ignored in Standby (use ?q=). Max 500 per run.
enginesstring[]all threeAny of brave, duckduckgo, mojeek. Keyless engines requiring a key are skipped with a warning.
braveApiKeysecret stringBrave Search API subscription token.
mojeekApiKeysecret stringMojeek Search API key.
countrystringusTwo-letter country code (Brave country, DDG region).
languagestringenTwo-letter language code (Brave search_lang, DDG region).
resultsPerEngineinteger101–50 organic results per engine per query.
mergeResultsbooleantrueMerge duplicates across engines (see below). false → one record per engine per result.
rerankbooleanfalseLLM re-rank merged results per query (needs openaiApiKey).
openaiApiKeysecret stringOnly used when rerank is true.
proxyConfigurationproxynoneDuckDuckGo only — regular egress if enabled, and always the retry path when DDG serves a CAPTCHA.

Declared outputs

The Actor ships a machine-readable .actor/output_schema.json, so Console, the API, and MCP clients know exactly what a run produces:

OutputWhere it livesWhat it is
resultsDefault dataset (/items)Every normalized SERP record — the main output
runSummaryKey-value store, key OUTPUTOne JSON object: queries/records processed, per-engine execution counts, engines skipped for missing keys, failures with reasons, warnings, and the exact PPE events charged
standbySearchEndpointThe run's container URL…/search — the live real-time endpoint while running in Standby

The dataset also ships a .actor/dataset_schema.json with typed, documented fields (so agents can interpret each column) and two views: Overview and Cross-engine consensus, which flattens enginesRanks into one column per engine to show which URLs several independent engines agree on.

Real OUTPUT summary from the sample run below:

{
"mode": "batch",
"startedAt": "2026-08-15T15:33:20.353Z",
"finishedAt": "2026-08-15T15:33:23.005Z",
"queries": 1,
"records": 10,
"settings": { "engines": ["duckduckgo"], "resultsPerEngine": 10, "mergeResults": true, "rerank": false, "country": "us", "language": "en" },
"engines": { "executedByEngine": { "duckduckgo": 1 }, "skipped": [] },
"charged": { "serp-query": 1, "rerank": 0 },
"failures": [],
"warnings": []
}

Note that the summary lives in the key-value store, not the dataset: every dataset item keeps one uniform shape, which is the point of this Actor for agent consumers.

Output schema & real sample

Each dataset record (and each element of the Standby results array):

FieldTypeNotes
querystringThe query that produced this record
enginestringProducing engine; for merged records, the best-ranked contributor
ranknumberRank within its engine; for merged records, the best rank across engines
title, url, snippetstringNormalized result fields
fetchedAtISO-8601 stringWhen the result was fetched
enginesRanksobjectMerged records only: { engine: rank } for every engine that listed this URL
rerankScorenumber 0–1Only when rerank ran: higher = more relevant

Real output from a local run with { "queries": ["apify actor pricing"], "engines": ["duckduckgo"] }:

[
{
"query": "apify actor pricing",
"engine": "duckduckgo",
"rank": 1,
"title": "Apify pricing - plans for data collection at any scale · Apify",
"url": "https://apify.com/pricing",
"snippet": "The Apify platform has a number of services that are charged based on usages, such as Actors, proxies, data transfer, and storage. See pricing for the full list of platform services. Each subscription plan comes with a certain amount of prepaid platform usage that is used to pay for services. If your platform usage in a given billing cycle exceeds this prepaid amount, the excess usage will be ...",
"fetchedAt": "2026-08-14T15:02:28.111Z",
"enginesRanks": { "duckduckgo": 1 }
},
{
"query": "apify actor pricing",
"engine": "duckduckgo",
"rank": 2,
"title": "Apify Actor Cost Estimator",
"url": "https://apify.com/agentictools/actor-cost-estimator",
"snippet": "Estimate what an Apify Actor will cost before you run it, across its pricing model and your workload.",
"fetchedAt": "2026-08-14T15:02:28.111Z",
"enginesRanks": { "duckduckgo": 2 }
},
{
"query": "apify actor pricing",
"engine": "duckduckgo",
"rank": 3,
"title": "How to Monetize Apify Actors: Pricing, Payouts & Publishing | Use Apify",
"url": "https://use-apify.com/docs/apify-for-developers/monetize-actors",
"snippet": "Monetize Apify Actors with pay-per-event, pay-per-result, or rental pricing. Commission split, PayPal and bank payouts, and steps to publish a paid Store listing.",
"fetchedAt": "2026-08-14T15:02:28.111Z",
"enginesRanks": { "duckduckgo": 3 }
}
]

How merging works

With mergeResults: true (default), URLs are canonicalized — tracking params (utm_*, gclid, fbclid, …) stripped, trailing slash removed, host lowercased, http/https folded — and results from different engines pointing at the same canonical URL become one record:

  • enginesRanks keeps every engine's rank: { "brave": 2, "duckduckgo": 1 } means both engines found it — a strong consensus signal for agents.
  • Title/snippet/rank come from the best-ranked contributor.
  • Output is ordered by best rank; ties go to results more engines agree on.

With mergeResults: false you get the raw per-engine view: one record per engine per result.

LLM re-ranking (optional)

With rerank: true and an openaiApiKey, one structured gpt-4o-mini call per query re-orders the merged results by relevance to the query intent and attaches rerankScore (0–1). If the call fails, the run continues with engine order — and the rerank event is not charged.

Pricing (pay-per-event)

EventDescriptionChargedSuggested price
serp-queryOne executed search of one query on one engine, including normalization, dedupe, and record deliveryPer query × engine actually executed — only after its records are stored$0.003
rerankOne AI relevance re-ranking pass over a query's merged results, adding rerankScorePer successfully re-ranked query — only after records are stored$0.005

Cost intuition: a 3-engine merged search is ~$0.009; a 100-query × 2-engine batch is ~$0.60. Skipped engines (missing key) and failed engine calls cost nothing.

Run it at 512 MB — measured peak memory is 76 MB, so the platform default of 4 GB just multiplies your compute bill. See MONETIZATION.md for the full Console setup and measured margins.

Three concrete use cases

  1. Agent web-search tool with a fixed unit cost. Wire the Standby endpoint (or MCP tool) into your agent framework as its web_search function. Finance knows exactly what 10,000 agent searches cost before the month starts.
  2. RAG freshness pipeline. Nightly batch run over your product's top 500 questions across all three engines; merged, deduped records feed your retrieval index with a cross-engine consensus signal (enginesRanks) for source weighting.
  3. Brand & SEO monitoring across independent indexes. Track where your domain ranks on Brave vs DuckDuckGo vs Mojeek for target keywords — three genuinely different indexes, one normalized dataset you can diff over time.

FAQ

Why bring my own Brave/Mojeek keys? Both offer official APIs with free tiers. BYO keys keep you inside each engine's terms, give you your own quota, and keep this Actor's per-query price flat regardless of your plan.

What happens if I only provide some keys? Engines without keys are skipped with a logged warning; everything else runs. DuckDuckGo always works keyless.

Is Google or Bing supported? Not in this Actor — it focuses on engines that are agent-friendly via official APIs or stable endpoints. For Google, use a dedicated Google SERP actor from the Store.

What if DuckDuckGo blocks the request? The engine retries once through your proxyConfiguration (fresh session), then returns whatever it parsed with a warning instead of failing the whole request. For heavy DDG use, enable residential proxy.

Do standby requests also write to the dataset? Yes — records are pushed to the run's default dataset and returned in the response, and charging happens only after the push succeeds.

How fresh are results? Every record carries fetchedAt. Nothing is cached by the Actor — every query hits the engines live.

Rate limits? Global concurrency is capped at 5 in-flight engine requests (DuckDuckGo held to 2), with exponential backoff honoring Retry-After on 429s.

Local development

npm install
npm run build # tsc — zero errors expected
npm test # unit tests: URL canonicalizer + standby server (engine calls mocked)
apify run # batch run against storage/key_value_stores/default/INPUT.json
# Local standby server on :3123 — APIFY_META_ORIGIN is what selects the mode,
# exactly as the platform does it (the port var alone is set on every run).
APIFY_META_ORIGIN=STANDBY ACTOR_STANDBY_PORT=3123 npm start

Changelog

0.1.0

  • Initial release: Brave / DuckDuckGo / Mojeek engines, cross-engine merge with enginesRanks, batch + Standby modes, optional LLM re-rank, pay-per-event charging (serp-query, rerank).