First scan walkthrough
For operators · running scans
TutorialThis tutorial takes you end-to-end on your first scan — installing
Adler, running it, reading the output, hitting Uncertain, fixing
Uncertain, watching the verdict improve, and saving the workflow for
next week. It’s longer than the Quickstart because the
goal here isn’t a 60-second demo; it’s making sure you actually
understand what Adler is doing before you scale it up.
You’ll spend about 15 minutes. By the end, you’ll have:
- A working install
- One real scan you’ve inspected
- A working remedy for at least one
Uncertainrow - A repeatable workflow (
--watch) for tracking the same name week to week
Step 1 — Install
Section titled “Step 1 — Install”Pick whichever path matches your machine; both arrive at the same
adler binary on PATH:
# Pre-built binaries (fastest)cargo binstall adler-cli
# Or compile from source (~1–2 min)cargo install adler-cliIf you want the TLS-fingerprint impersonation
transport (Chrome 134 handshake emulation; needed for some sites tagged
protection: tls-fingerprint), add --features impersonate to the
cargo install flavour. The binstall flavour ships impersonate
pre-built on 4/5 supported targets.
Confirm:
adler --version# adler 0.11.0The Install page covers every flavour in more depth if you hit a build error.
Step 2 — Your first scan
Section titled “Step 2 — Your first scan”Pick a username you know exists on at least one site — a real human’s
GitHub handle works. We’ll use torvalds:
adler torvaldsWhat you see:
- Text streams in as outcomes resolve — that’s the default
interactive renderer. Found rows in green, Uncertain rows in amber,
NotFound rows hidden by default (pass
--allto include them). - Categorised —
dev,social,forum, etc., based on each site’s tags. - Per-row metadata at the right — elapsed time, verdict reason for Uncertain rows, the transport chip when it’s not plain HTTP.
Expect mostly Found for torvalds (he’s on a lot of dev platforms)
and a sprinkle of Uncertain (CDN edges, login walls).
Step 3 — Understanding the output
Section titled “Step 3 — Understanding the output”The verdict model is the most important thing in Adler. Three states:
| State | What it means | Trust it? |
|---|---|---|
Found | The site returned a working response that confirms the account exists. | Yes. |
NotFound | The site returned a working response that confirms the account does not exist. | Yes. |
Uncertain(reason) | The site responded, but the response can’t tell Found from NotFound. The reason says why. | No — and you should figure out why. |
Adler’s whole identity is in that third row. See
Honest verdicts for the philosophy; the practical
implication is: an Uncertain is not a failure of Adler, it’s
information about the site or your network.
For the verdict reasons, inspect any individual row with --explain:
adler --explain --only github,gitlab torvaldsYou’ll see the signal that produced each verdict. On Found, that’s
the matching status / body marker / redirect rule. On Uncertain,
it’s the UncertainReason — typically
something like cloudflare_challenge, rate_limited, geo_unavailable,
or session_required.
Step 4 — Why is anything Uncertain?
Section titled “Step 4 — Why is anything Uncertain?”Almost always the answer is your scan source. Datacenter IPs (the
default for cloud VMs and most home dev boxes routed through corporate
egress) are pre-banned at CDN edges like Cloudflare and Akamai. From
those IPs, sites that work fine in a browser return interstitial
challenges to plain HTTP — and Adler honestly reports
Uncertain(cloudflare_challenge) rather than guessing.
To confirm this is what’s happening, pipe a JSON dump through jq:
adler --format ndjson torvalds | \ jq -r 'select(.kind == "uncertain") | "\(.site)\t\(.reason)"' | \ sort | uniq -c | sort -rnIf the top reasons are cloudflare_challenge / rate_limited —
that’s a network problem, not an Adler bug. Step 5 fixes it.
If the top reason is geo_unavailable — that site has an access
policy that needs a country-specific egress;
see Access engine → Egress pool.
If the top reason is session_required — that site needs a logged-in
session; see Access engine →
Sessions.
Step 5 — Your first remedy
Section titled “Step 5 — Your first remedy”Cheapest first: tell Adler to route through a residential proxy. Any SOCKS5 or HTTP proxy you control works — paid residential pools (BrightData, DECODO, IPRoyal, Smartproxy) typically give you the best ratio of low ban rate per dollar, but a Tor exit also works in a pinch (slow, but unbanned by most non-Cloudflare edges):
adler --proxy socks5://USERNAME:PASSWORD@HOST:PORT torvalds# Or, for a one-off Tor sweep:adler --tor torvaldsRe-run the jq aggregation from Step 4 against the new output. The
cloudflare_challenge and rate_limited rows should shrink dramatically
— sometimes to zero.
If you want to handle the bot-protected subset (Instagram, X) too,
add a browser backend on top:
adler --proxy socks5://... \ --browser-backend local \ torvaldsLocal Chrome (--browser-backend local) is free; Browserbase’s cloud
sessions (--browser-backend browserbase, ~$0.05/min) buy you a
residential-IP-with-anti-fingerprinting backend for the bot-protected
edge cases. Both bounded by --browser-budget (default 50 fetches per
scan) so a misconfigured flag can’t burn a quota.
Step 6 — Compare the before and after
Section titled “Step 6 — Compare the before and after”You can prove the remedy worked with the built-in cache + the Doctor:
# Save the "before" snapshotadler --format ndjson torvalds > before.ndjson
# Switch to remedied config and re-scanadler --proxy socks5://... \ --browser-backend local \ --format ndjson torvalds > after.ndjson
# Diff the verdict countsfor f in before.ndjson after.ndjson; do echo "=== $f ===" jq -r '.kind' "$f" | sort | uniq -cdoneExpected shape: found goes up, uncertain goes down. NotFound stays
roughly flat (unless Adler now sees sites where the proxy IP is itself
banned — possible but rare on quality residential pools).
Step 7 — Make it a workflow
Section titled “Step 7 — Make it a workflow”Two patterns to graduate from “one-off scan” to “I monitor this name”:
Pattern A — watch mode. Re-scan periodically and surface diffs:
adler --watch torvalds # diff vs last cached runadler --watch --interval 86400 torvalds # re-scan every 24hThe watch mode keeps the scan cache at ~/.cache/adler/ and prints
only the rows that changed — new accounts, removed accounts, flipped
verdicts. Pipe it into your alert channel of choice.
Pattern B — Web UI for visual review. If you want a real interface with history, side-by-side diff, evidence drawers, and the access engine view, launch the bundled SPA:
adler --web# http://127.0.0.1:8080See the Web UI page for the full feature tour.
What you’ve learned
Section titled “What you’ve learned”- Adler’s three-verdict model and why
Uncertainis information, not failure. - How to inspect verdict reasons with
--explainand--format ndjson. - That datacenter IPs cause most
Uncertains and how to remedy them. - How to layer a residential proxy + browser backend.
- Two workflow patterns for tracking a name over time.
Where to read next
Section titled “Where to read next”- Access engine — the full toolkit (browser backend, escalation, egress pool, sessions, impersonation) once you hit edge cases this tutorial didn’t cover.
- Web UI — the SPA’s feature tour, including per-scan egress subset selection from the Advanced filters modal.
- Honest verdicts — the philosophy doc behind the three-verdict model.
- FAQ — common edge cases and gotchas.
- Glossary — terminology lookup.