# Perplexed v0.2.0 - Table of Contents > A small Perplexity-style web search and answer toolkit for Elixir: swappable search providers, page scraping, and cited answers on any ReqLLM model. ## Pages - [Perplexed](readme.md) ## Modules - [Perplexed](Perplexed.md): A small web search, scrape and research toolkit, in the spirit of Firecrawl or Exa. - Search - [Perplexed.Search](Perplexed.Search.md): Swappable web search: every provider takes a query and returns normalized `Perplexed.Search.Hit`s, so callers change engines by changing one option. Built-in providers, by name, with list price per successful request (USD, as of 2026-11-10) used for per-run cost accounting - [Perplexed.Search.Cloudflare](Perplexed.Search.Cloudflare.md): Cloudflare Web Search API (through AI Gateway) as a `Perplexed.Search` provider. - [Perplexed.Search.DeepSeek](Perplexed.Search.DeepSeek.md): DeepSeek Search API (`POST /v1/tools/search`) as a `Perplexed.Search` provider. - [Perplexed.Search.Fallback](Perplexed.Search.Fallback.md): Opt-in provider fallback: a list of provider specs, tried in order until one answers, such as free first and paid last - [Perplexed.Search.Firecrawl](Perplexed.Search.Firecrawl.md): Firecrawl v2 search as a `Perplexed.Search` provider. - [Perplexed.Search.Fusion](Perplexed.Search.Fusion.md): Merges ranked hit lists from several sources (SearXNG instances, search engines) into one list: de-duplicates by normalized URL, scores by reciprocal rank, boosts hits several engines agree on, and demotes hits that share no terms with the query. - [Perplexed.Search.Hit](Perplexed.Search.Hit.md): One search result, normalized across providers. - [Perplexed.Search.Result](Perplexed.Search.Result.md): One search call: the hits, the provider that answered, and what it cost. - [Perplexed.Search.SearXNG](Perplexed.Search.SearXNG.md): Keyless web search through SearXNG metasearch instances, as a `Perplexed.Search` provider (`:searxng`). Free: price 0. - [Perplexed.Search.SearXNG.Directory](Perplexed.Search.SearXNG.Directory.md): Picks public SearXNG instances from searx.space's daily health check (`https://searx.space/data/instances.json`). - [Perplexed.Search.SearXNG.Instances](Perplexed.Search.SearXNG.Instances.md): The live set of public SearXNG instances, discovered instead of hard-coded. Set `searxng_instances: :auto` and `Perplexed.Search.SearXNG` asks this store for its instances. - [Perplexed.Search.SearXNG.Pool](Perplexed.Search.SearXNG.Pool.md): Health, speed and rate-limit state for SearXNG instances, learned from the searches this node makes. One pool runs under the `:perplexed` application; tests and hosts can start more with `:name`. - Scrape - [Perplexed.Document](Perplexed.Document.md): One scraped page as Markdown, with how it was obtained. - [Perplexed.PdfConverter](Perplexed.PdfConverter.md): The behaviour that turns PDF bytes into Markdown for a scrape. - [Perplexed.Scrape](Perplexed.Scrape.md): Scrapes a URL to Markdown by climbing a ladder of `Perplexed.Scraper`s, cheapest first. - [Perplexed.Scraper](Perplexed.Scraper.md): The behaviour of one scrape tier, and the registry of built-in tiers. - [Perplexed.Scraper.BrowserRun](Perplexed.Scraper.BrowserRun.md): Cloudflare Browser Run `/markdown` quick action as a `Perplexed.Scraper`: loads the URL in headless Chrome, runs its JavaScript, and returns the rendered page as Markdown. - [Perplexed.Scraper.DeepSeek](Perplexed.Scraper.DeepSeek.md): DeepSeek Fetch API (`POST /v1/tools/fetch`) as a `Perplexed.Scraper`: DeepSeek fetches the URL and returns the page as Markdown. - [Perplexed.Scraper.Direct](Perplexed.Scraper.Direct.md): Plain HTTP as a `Perplexed.Scraper`, sending browser-like request headers. Free and fast; the first tier of the default ladder. - [Perplexed.Scraper.Firecrawl](Perplexed.Scraper.Firecrawl.md): Firecrawl v2 scrape as a `Perplexed.Scraper`. - [Perplexed.Scraper.Impersonated](Perplexed.Scraper.Impersonated.md): HTTP through `CloakedReq` (Rust wreq) as a `Perplexed.Scraper`: the request carries a real browser's TLS and HTTP/2 fingerprint and headers, which gets past sites that refuse plain clients on that signal alone. - [Perplexed.Verdict](Perplexed.Verdict.md): Judges whether fetched page text is worth handing to a model. - Answer - [Perplexed.Answer](Perplexed.Answer.md): The result of `Perplexed.answer/2`. - [Perplexed.Answer.Candidate](Perplexed.Answer.Candidate.md): One unique search hit an answer considered. - [Perplexed.Answer.Source](Perplexed.Answer.Source.md): One page an answer was written from. `number` is its citation number; `tier` is the scraper that read it and `cost` what reading it cost. - [Perplexed.Passages](Perplexed.Passages.md): Chooses which parts of a long page a model gets to read. - [Perplexed.Pipeline](Perplexed.Pipeline.md): One-shot web answering, in fixed steps - Infrastructure - [Perplexed.Config](Perplexed.Config.md): Perplexed's settings. - [Perplexed.Telemetry](Perplexed.Telemetry.md): `:telemetry` events Perplexed emits. Attach handlers to track spend or to be told when a provider needs attention. - [Perplexed.UrlGuard](Perplexed.UrlGuard.md): Refuses URLs that would point a scrape at a private network. ## Mix Tasks - [mix perplexed.searxng.instances](Mix.Tasks.Perplexed.Searxng.Instances.md): Fetches today's public SearXNG instances from searx.space, probes each start page from this machine, and prints which are up, fastest first. - [mix tidewave](Mix.Tasks.Tidewave.md): Starts the app and serves Tidewave's MCP at `http://localhost:/tidewave/mcp` so a coding agent can evaluate code inside the running project. Tidewave ships only as a Phoenix plug, so this runs that plug under Bandit for a library with no endpoint.