Adler
Named for Irene Adler β "the Woman", the one who outwitted Sherlock Holmes. Where Sherlock searched, Adler outsmarts.
OSINT username search across ~3,000 sites, in Rust. Honest verdicts and built to reach the hard ones β Cloudflare-walled, TLS-fingerprinted, geo-restricted, login-walled.
Documentation
- π adler-docs β the user manual: install, the access engine, the web UI, embedding, FAQ.
- π¦ docs.rs/adler-core β Rust API reference.
- πΊοΈ PLAN.md β roadmap and the design behind the access-engine phases.
This README covers the elevator pitch (compare table, detection rate data) plus install / quickstart; deeper material lives on the docs site so it can evolve independently of crate releases.
How Adler compares
Open-source username-search tools that OSINT operators actually consider, on the dimensions that matter when sites push back:
| Sherlock | Maigret | Blackbird | Snoop | Adler | |
|---|---|---|---|---|---|
| Approx. sites | 400 | 3,000 | 600 | 5,400 | 3,000 [^cmp-1] |
| Verdict model | Found / NotFound | Found / NotFound | Found / NotFound | Found / NotFound | Found / NotFound / Uncertain(reason) |
| Bot-protected sites (Instagram, X, β¦) | β | β | β | β | headless Chrome via --browser-backend |
| TLS-fingerprint blocking | β | β | β | β | Chrome 134 handshake via --features impersonate |
| Proxy routing | one global | one global + Tor + I2P | β | β | one global or per-site policy via --proxy-pool |
| Cookies / sessions | β | global cookies.txt |
β | β | per-site named sessions via --sessions |
| Registry self-heal | β | β | β | β | --doctor --fix diffs responses, proposes new signatures |
| Web UI | β | yes (results graph, reports) | β | β | --web β live SSE-streaming SolidJS SPA + JSON API |
| Output formats | text / CSV / XLSX / JSON | text / JSON / CSV / HTML / PDF / XMind / D3 | text / CSV / PDF | text / CSV / HTML | text / JSON / NDJSON / CSV / HTML |
| Embeddable library | β | yes (Python async) | β | β | adler-core on crates.io (Rust) |
| Runtime / packaging | Python | Python | Python | Python | Rust β single static binary, cargo binstall |
[^cmp-1]: Sherlock + Maigret + WhatsMyName lineages combined; see Site registry.
Adler's thesis: honest verdicts plus access for the sites that matter. A
NotFound from a Python-HTTP-only tool on a Cloudflare-walled, TLS-
fingerprinted, geo-restricted, or login-walled site is often just "I gave up
at the first wall." Adler reports Uncertain(reason) when it couldn't verify,
and ships the transports you need to break the wall yourself β headless
browser, Chrome handshake emulation, per-site geo / IP-type egress, operator-
supplied sessions. We do not solve CAPTCHAs or evade human-verification (see
Ethics & responsible use).
Detection rate
Recall depends on where you scan from. A --doctor pass on 2026-05-26
against the bundled registry (411 sites):
| Scan source | Sites where a known-existing account is found | Recall |
|---|---|---|
| Datacenter IP (Hetzner / Leaseweb DE) | 282 / 411 | 68.6% |
| US residential proxy pool (DECODO) | 305 / 411 | 74.2% |
The residential lift is real: ~40 sites swap their verdict between
Uncertain (datacenter) and Found (residential) β most are
Cloudflare-walled or geo-restricted (RU-segment, plus platforms like
Reddit, Imgur, Patreon). The remaining ~26% breaks down roughly as:
- Bot-protected sites tagged
bot-protected(Instagram and X/Twitter today) β these serve a JS login wall to a plain HTTP request; a clean IP doesn't help, you need a browser backend. Exclude them with--exclude-tag bot-protected. - Stale Sherlock-imported
known_presentaccounts that no longer exist on the live site. The--doctor --suggest-known-presenttool (new in v0.4.0) probes a small candidate pool (the site's brand name, plustorvalds/octocat/admin/ β¦) and prints a paste-ready snippet for any site where it finds a live account. Discovery surfaced 19 healable entries on the most recent sweep; the remaining placeholders need either a contributor-found candidate or a deeper repair via--doctor --fix. - Sites whose detection rule fires for every username β
signal repair territory, not username repair.
--doctor --fixdiffs the responses and proposes a tighter signal. - Sites that don't reliably distinguish found from not-found for unauthenticated requests at all β investigated and not added rather than ship false-positive entries: Reddit, TikTok, Pinterest, and Threads. See issues #11β#14 for the specific failure modes and what would unblock each.
Run the same check yourself: adler --doctor (uses your current IP)
or adler --doctor --proxy <url> (via your own proxy). With
--browser-backend browserbase the doctor's --fix mode routes
bot-protected sites through a real Chrome session, so the diff sees
real profile pages rather than two identical login walls. With
--suggest-known-present you get an OVERRIDES block per healable
site.
Crates
| Crate | Kind | Purpose |
|---|---|---|
adler-core |
lib | Detection engine, site registry, executor. |
adler-server |
lib | HTTP API + SSE streaming + scan persistence; embeds the SolidJS web UI via rust-embed. |
adler-cli |
bin | adler command-line interface; --web launches the embedded server + UI in-process. |
Install
From crates.io (compiles locally, ~1β2 min):
Pre-built binary from the GitHub release (instant, no compile):
From source:
Requires Rust β₯ 1.85. The installed binary is adler. The library
(adler-core) is published separately
for embedding the engine in your own tools β see the
Library section below.
Build & run
Logging is controlled by the ADLER_LOG env var (defaults to adler=info):
ADLER_LOG=adler=debug
Usage
adler <username> scans the embedded registry; everything else is a
knob. Text output shows Found and Uncertain by default and hides
NotFound β pass --all for the full list. Results stream into a
terminal as they resolve; piped output is collected and ordered. Exit
codes: 0 found, 1 nothing found, 2 error.
A few of the most common knobs:
β Complete flag reference, grouped by intent (filtering / output /
network & sessions / browser & cache / batch & enrichment), is on the
Usage page.
adler --help lists every flag with its short doc; the docs page adds
the bigger picture.
Web UI
adler --web boots a small in-process HTTP server and serves a SolidJS
SPA from the same binary β live SSE-streamed scans, persisted history,
side-by-side diff against an earlier run, a read-only access-engine
panel, and per-scan egress subset selection when a --proxy-pool is
loaded.
Warning β the default bind is loopback. Switching to
0.0.0.0exposes the JSON API to your network. Adler is not built to face the open internet; put auth in front of any non-loopback bind.
β The
Web UI page
covers the full feature set, the /api/* surface, and the deployment
notes (the SPA is rust-embed'd into the binary; rebuild from source
with npm ci && npm run build in adler-server/web/).
Access engine
Adler ships a transport ladder for sites a plain HTTP client can't see β that's the whole reason it scores ahead of Sherlock / Maigret on the hard subset of the registry:
- Browser backend (
--browser-backend local/browserbase) β real headless Chrome for sites taggedbot-protected(Instagram, X / Twitter today). Bounded by--browser-budgetso a misconfigured flag can't burn a quota. - TLS-fingerprint impersonation (
cargo install --features impersonate) β in-process Chrome 134 BoringSSL handshake for sites taggedprotection: tls-fingerprint. Much cheaper than a real browser. - Egress pool (
--proxy-pool <file>) β per-site geo / IP-type routing. Sites with anaccesspolicy pick a matching proxy; sites without stay on the default egress. - Sessions (
--sessions <file>) β operator-supplied cookies / tokens for login-walled sites. Per-site[name]tables; values redacted from logs. - Automatic escalation (
--escalation-budget N/--no-escalation) β when the cheap path returnsUncertain(cloudflare_challenge | rate_limited), the router automatically retries through the browser backend. Bounded by its own budget. Outcomes carrytransportandescalationstelemetry so it's clear which path produced each verdict.
β Full guide with the TOML formats, guardrails, and trade-offs lives at Access engine.
Library
adler-core is the runtime-agnostic engine that powers the CLI,
published separately on crates.io
for embedding in your own Rust tools β a Discord bot that checks
usernames, a security tool that flags exposed identities across a
watchlist, a CI gate that asserts a name isn't claimed elsewhere.
[]
= "0.10"
= { = "1", = ["macros", "rt-multi-thread"] }
β Minimal worked example, the notable ClientBuilder knobs, and the
per-version breaking-change log are on the
Embedding
page. The complete API reference is on
docs.rs/adler-core.
Site registry
The default registry (adler-core/data/sites.json, ~2.5k sites) is
generated from MIT-licensed upstream data β Sherlock + Maigret + an
opt-in WhatsMyName tranche (CC BY-SA 4.0; pass --no-wmn to drop it
when redistributing scan output under MIT only). Detections are imported
unverified β adler --doctor validates every signal, --doctor --fix proposes corrected ones.
β Detailed lineage, schema, signal model, and doctor workflow live in Site registry.
Troubleshooting
Common questions ("Why is everything Uncertain?", "Why does Adler find fewer accounts than Sherlock?", "How do I scan Instagram?", β¦) are covered in the FAQ on the docs site.
For CI / contributor-facing commands (cargo fmt, cargo clippy,
cargo test), see CONTRIBUTING.md.
Ethics & responsible use
Adler aggregates publicly reachable profile URLs, but aggregation makes intrusion easy β please use it responsibly.
Intended uses: checking your own accounts; authorized penetration tests and bug-bounty engagements; security research; and OSINT investigations with a lawful basis. Do not use Adler to stalk, harass, dox, or surveil people without authorization, or to mass-target individuals.
Detect, never circumvent. Adler reports anti-bot responses (rate limits,
Cloudflare challenges, captchas) as Uncertain β it does not solve captchas
or bypass access controls. It rate-limits per host, supports --max-rps and
--respect-robots, and writes an optional --audit-log of every request.
See SECURITY.md and CODE_OF_CONDUCT.md.
License
The Adler code is licensed under the MIT License.
The default site registry (adler-core/data/sites.json) is also under MIT
β it is derived from the Sherlock project (MIT) and the Maigret project
(MIT). See the file's _comment header and the corresponding importer
scripts in scripts/ for attribution.
The supplementary registry (adler-core/data/sites_wmn.json, included
by default; opt-out with adler --no-wmn) is derived from WhatsMyName
and licensed CC BY-SA 4.0. Adler's MIT licence
does not cover this file; downstream redistribution must preserve
attribution and the ShareAlike obligation on derivative data.