fastCRW scrapes and searches in Rust, and its own repository files disagree on where it lives, how big it is, and who may use it
Fast, lightweight Firecrawl/Tavily alternative in Rust. Web scraper, crawler & search API with MCP server for AI agents. Drop-in Firecrawl-compatible API (/scrape, /crawl, /search). 2.3x faster than Tavily, 1.5x faster than Firecrawl in 1K-URL benchmarks. 6 MB RAM, single binary. Self-host or use managed cloud.
At a glance
- What is it?
- fastCRW is a Rust workspace of eleven crates that turns URLs into markdown or schema JSON through one engine for search, scrape, map, crawl, and extract, with a CLI, Python and TypeScript SDKs, and an MCP server. The interesting reading is in the build files: a DNS resolver swapped for Docker compatibility, a TLS client held back from a licence change, a container that binds all interfaces by default, and three different licences.
- Who is it for?
- fastCRW is worth a look if you want a single binary scraper with a Firecrawl-shaped API and an MCP server, and if you read its BENCHMARKS.md and compatibility notes rather than its headline numbers, because the repository description and the README do not tell the same story about speed or memory.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- us/crw1,255 ★ · +287
| Repository | 2026-09-10 | 2026-11-14 |
|---|---|---|
| us/crw | 968 | 1.3k |
287 Stars in the last 65 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The tree lives at us/crw and every URL inside it points at fastcrw/crw
The repository is reachable under one owner and describes another. Cargo.toml declares `repository = "https://github.com/fastcrw/crw"`, the contributor instructions say to `git clone https://github.com/fastcrw/crw`, and the star history chart is wired to the `us/crw` path. So the code is published under one name and every internal link points at another, and a `.mailmap` sits in the root to reconcile contributor identities across the move. The homepage field is `https://fastcrw.com`, and the install path does not come from either repository at all: it is `curl -fsSL https://fastcrw.com/install | sh`, a script fetched from a domain and piped into a shell. Whatever a self-hoster pins in version control, the onboarding path is a remote script that can change without a commit.
Three licences for one project and one of them is an address
The licence paragraph splits the project three ways. The engine and the MCP server are AGPL-3.0, the Python and TypeScript SDKs are MIT, and the embedding licence is given as `[email protected]`, an email address rather than a licence identifier. Cargo.toml agrees only with the first part, setting the workspace `license = "AGPL-3.0"` for all eleven crates, which is the conservative reading rather than the accurate one. Nothing else in the tree repeats the split, and no file in the root listing names the embedding terms. The practical consequence is that the two binaries you install with the one-line installer are the covered part, while the libraries you import from Python or Node are the permissive part, and the question of whether a given use counts as an embedding is answered by emailing the project rather than by reading a licence file.
The Compose file publishes port 3000 on every interface
The port mapping in docker-compose.yml is a single line with a long comment above it, and both halves matter:
- "${CRW_BIND_ADDRESS:-0.0.0.0}:${CRW_HOST_PORT:-3000}:3000"The default bind address is `0.0.0.0`, so an unmodified `compose up` publishes the engine on all interfaces rather than on loopback, and the comment says as much. The override knobs are `CRW_BIND_ADDRESS` and `CRW_HOST_PORT`, namespaced to `crw` so they cannot collide with a generic `HOST_PORT` in the operator's environment. The trap is in the same comment: despite the `CRW_` prefix these are Compose-only host-side interpolations, they are not passed into the container, and the engine's own figment configuration never sees them. Setting `CRW_BIND_ADDRESS=127.0.0.1` when fronting crw with a reverse proxy is the documented way to close the default, and the container port itself stays 3000 either way.
lightpanda is required, chrome is opt-in, and the stealth profile is SSPL
The dependency block encodes three different levels of optionality. `lightpanda` is listed with `condition: service_started` and no `required` flag, so Compose waits for it and treats it as part of the stack. `chrome` is opt-in through `--profile heavy` and is listed with `required: false`, so a missing service is not an error. `chrome-stealth` is opt-in through `--profile stealth` and is also `required: false`, but the comment attaches a licence condition: it is a browserless image and is SSPL-licensed, to be run only if you accept those terms. The two profiles are called mutually exclusive in practice, so a deployment picks one. `searxng` is gated on `condition: service_healthy` rather than merely started, because it backs `/v1/search` and a search issued right after `compose up` would otherwise race its cold start.
The DNS resolver was swapped and the TLS client was held back
Two dependency comments record decisions that read like archaeology and are worth treating as design notes. The first explains why the HTTP client uses reqwest's default system resolver with no `hickory-dns`: getaddrinfo reads `/etc/resolv.conf` natively, so it resolves external CNAME chains and internal service names through Docker's embedded DNS at 127.0.0.11, where the hickory resolver had failed on direct egress for managed LLM and research APIs. getaddrinfo runs on tokio's blocking pool, which is why it does not stall the async runtime. The second covers Chrome TLS, JA3, and HTTP2 impersonation: only `crw-renderer` references that client, behind an `impersonated` feature, and wreq-util is held at 0.2 because that line is Apache-2.0 while the later 3.0.0-rc line is LGPL and described as deliberately avoided. The same dependency block disables reqwest's default features and re-enables them one by one, including rustls, brotli, socks, streaming, and multipart.
Two hours per arm64 release became minutes, and the cache is a tagged image
The Dockerfile comment is the clearest statement of build economics in the repository. The builder used to run under QEMU for linux/arm64, emulating the entire Rust compile for roughly two hours per release; it now runs on the native build platform and cross-compiles to the requested target, bringing arm64 back to minutes, with only the runtime layer holding ca-certificates still touching QEMU. Dependency caching is cargo-chef, and the cacher stage is keyed only on the Cargo manifests, so a source-only change leaves the recipe byte-identical and only workspace crates recompile. Durability comes from tagging: production bakes the cacher stage as `crw-api-deps:<fp>` and points the builder at it, so tagged layers are referenced rather than dangling and a nightly `docker image prune -f` cannot evict them. The same file also drops two binaries from the production build, since the engine container only runs `crw-server` and linking `crw-cli` and `crw-mcp` there is wasted work.
One shell command installs the binary and registers it with your tools
The quick start is three commands and one environment variable. `curl -fsSL https://fastcrw.com/install | sh` installs a local binary with no account, and `curl -fsSL https://fastcrw.com/install | CRW_API_KEY=crw_live_... sh` installs it, connects a cloud key, and registers the MCP server. The installer detects Claude Code, Cursor, Codex, Gemini CLI, OpenCode, and Windsurf when they are already configured, touches nothing else, and keeps your key in `~/.config/crw/config.toml` rather than copying it into each tool. `CRW_NO_AGENTS=1` skips that step, and `crw setup` runs it interactively on its own. Platforms are macOS and Linux on Intel and ARM. Against all of that, the two headline claims do not match: the repository description says 2.3x faster than Tavily, 1.5x faster than Firecrawl, and 6 MB of RAM, while the README says it recovered more truth than Crawl4AI and Firecrawl, matched the fastest median latency, and idled at about 14 MB.
Eleven crates, an excluded fuzz target, and three releases in two days
The workspace lists eleven members: crw-core, crw-diff, crw-renderer, crw-extract, crw-crawl, crw-search, crw-server, crw-mcp, crw-mcp-proto, crw-browse, and crw-cli, on edition 2024 with resolver 2 and version 0.37.2. One top-level directory is deliberately kept out of that list, because the workspace carries `exclude = ["fuzz"]` while the repository still holds both `fuzz/` and a `.clusterfuzzlite/` configuration. `Cross.toml` sits alongside for cross-compilation. Releases are automated rather than manual, with `.release-please-manifest.json` and `release-please-config.json` next to CHANGELOG.md and RELEASE.md, and the published tags match the workspace version: v0.37.0 on 2026-09-29, then v0.37.1 and v0.37.2 on the same day, 2026-09-30, hours apart. The root also carries a lone `test_api_pipeline.py` beside the Rust tree, and the root package.json declares exactly one dependency, `marked` at 18.x. Next to all of it sit COMPATIBILITY.md, COMPATIBILITY-firecrawl.md, BENCHMARKS.md, CONVENTIONS.md, and a second README in Chinese.
Editorial conclusion
fastCRW is worth a look if you want a single binary scraper with a Firecrawl-shaped API and an MCP server, and if you read its BENCHMARKS.md and compatibility notes rather than its headline numbers, because the repository description and the README do not tell the same story about speed or memory. It is a poor fit for an AGPL-averse deployment that also needs the SDKs under a permissive licence, since the split is by component and not by deployment, and a poor fit if you plan to run the bundled Compose file unchanged, since it publishes port 3000 on every interface by default. Before deploying, read the licence paragraph line by line, decide what the SSPL stealth browser means for you, and check that the repository you clone matches the URLs your tooling will follow.
Frequently asked questions
What is fastCRW and what operations does it support?
It is a Rust engine for turning URLs into markdown or structured JSON, covering scrape, crawl, map, search, and extract. Scrape turns one URL into markdown, HTML, links, screenshots, or schema JSON, crawl follows a bounded site crawl, map discovers URLs without scraping every page, search queries the web and can optionally scrape selected results, and extract produces structured fields from one or many URLs.
What licence is fastCRW under?
It is split by component: the engine and the MCP server are AGPL-3.0, the Python and TypeScript SDKs are MIT, and the embedding licence is given as an email address, [email protected]. Cargo.toml sets AGPL-3.0 for the whole workspace, which is the conservative reading rather than the full split, and no file in the repository states the embedding terms.
How do I install fastCRW?
With `curl -fsSL https://fastcrw.com/install | sh` for a local, account-free install, or `curl -fsSL https://fastcrw.com/install | CRW_API_KEY=crw_live_... sh` to also connect a cloud key and register the MCP server. macOS and Linux are supported on Intel and ARM. Building from source needs Rust 1.85 or newer, after which `make check-fast` runs the fast checks.
What does the bundled docker-compose.yml start?
Four services with different optionality: lightpanda is waited on with condition service_started, chrome is opt-in through `--profile heavy`, chrome-stealth is opt-in through `--profile stealth` and is an SSPL-licensed browserless image you should only run if you accept those terms, and searxng backs `/v1/search` and is gated on condition service_healthy. The container listens on 3000 and publishes on 0.0.0.0 by default.
What benchmarks does fastCRW publish?
On Firecrawl's own public 1,000-URL dataset it reports recovering more truth than Crawl4AI and Firecrawl while matching the fastest median latency, idling at about 14 MB of RAM, with methodology in BENCHMARKS.md. Separately, on the 600 AA-Omniscience questions it reports answering 90.0% correctly, with a 14-product comparison published alongside it.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/us-crw)Star history chart for your README
[](https://hysenlabs.com/projects/us-crw)Was this useful?