Skip to content

First scan walkthrough

For operators · running scans

Tutorial

This 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, exporting a case file, 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
  • Signal evidence and confidence reasons you can explain
  • A working remedy for at least one Uncertain row
  • A case-file export path for handoff or downstream tooling
  • A repeatable workflow (--watch) for tracking the same name week to week

Pick whichever path matches your machine; both arrive at the same adler binary on PATH:

Terminal window
# Pre-built binaries (fastest)
cargo binstall adler-cli
# Or compile from source (~1–2 min)
cargo install adler-cli

If 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:

Terminal window
adler --version
# adler 0.15.0

The Install page covers every flavour in more depth if you hit a build error.


Pick a username you know exists on at least one site — a real human’s GitHub handle works. We’ll use torvalds:

Terminal window
adler --explain torvalds

What 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 --all to include them).
  • Categoriseddev, social, forum, etc., based on each site’s tags.
  • Per-row metadata — elapsed time, verdict reason for Uncertain rows, confidence score when available, and the transport chip when it’s not plain HTTP.
  • Explainability lines--explain prints the signal evidence, confidence reasons, and any structured profile evidence attached to the outcome.

Expect mostly Found for torvalds (he’s on a lot of dev platforms) and a sprinkle of Uncertain (CDN edges, login walls).


The verdict model is the most important thing in Adler. Three states:

StateWhat it meansTrust it?
FoundThe site returned a working response that confirms the account exists.Yes.
NotFoundThe 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.

Confidence is the second thing to read. It is conservative and explainable: signal evidence, exact username matches, authenticated access, browser/impersonate transports, rich profile metadata, and stable history can raise it; weak status-only results, blocked transports, session-required paths, CAPTCHA, and rate-limits keep it low. The reasons are printed by --explain and are serialized in JSON, Web, MCP, and reports.

For a focused explanation pass, inspect a small subset:

Terminal window
adler --explain --only github,gitlab torvalds

You’ll see the signal that produced each verdict. On Found, that’s the matching status / body marker / redirect rule, plus confidence reasons such as found by detection signal or exact username match. On Uncertain, it’s the UncertainReason — typically something like cloudflare_challenge, rate_limited, geo_unavailable, or session_required.

When you need profile evidence for correlation, add enrichment:

Terminal window
adler --enrich --explain --only github,gitlab torvalds

Structured profile_evidence is intentionally narrow: display names, bio snippets, avatar URLs, external links, locations, exact username evidence from explicit registry signals, and opt-in avatar hashes. Identity clusters use these structured fields; username-only overlap is not enough to merge accounts.


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:

Terminal window
adler --format ndjson torvalds | \
jq -r 'select(.kind == "uncertain") | "\(.site)\t\(.reason)"' | \
sort | uniq -c | sort -rn

If 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.


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):

Terminal window
adler --proxy socks5://USERNAME:PASSWORD@HOST:PORT torvalds
# Or, for a one-off Tor sweep:
adler --tor torvalds

Re-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:

Terminal window
adler --proxy socks5://... \
--browser-backend local \
torvalds

Local 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.


You can prove the remedy worked with the built-in cache + the Doctor:

Terminal window
# Save the "before" snapshot
adler --format ndjson torvalds > before.ndjson
# Switch to remedied config and re-scan
adler --proxy socks5://... \
--browser-backend local \
--format ndjson torvalds > after.ndjson
# Diff the verdict counts
for f in before.ndjson after.ndjson; do
echo "=== $f ==="
jq -r '.kind' "$f" | sort | uniq -c
done

Expected 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).


When a result is leaving your terminal, export an investigation report instead of handing over raw scan rows. Reports combine summary counts, found accounts, high-confidence accounts, signal evidence, normalized profile evidence, confidence reasons, identity clusters, timeline events, and limitations.

The easiest route is the Web UI:

Terminal window
adler --web
# Open http://127.0.0.1:8080, run a scan, wait for Done, use JSON / Markdown / HTML exports.

The scan id is visible in the route (#/scan/<id>). The same persisted scan can be rendered from the CLI:

Terminal window
adler --report-scan <SCAN_ID> > report.md
adler --report-scan <SCAN_ID> --report-format json > report.json
adler --report-scan <SCAN_ID> --report-format html > report.html

Use Markdown for notes and tickets, JSON for downstream tools, and HTML for a self-contained local case file. HTML reports are offline-safe: inline CSS, no JavaScript, and no automatic external avatar/image loads. See Investigation reports for the full report model.


Two patterns to graduate from “one-off scan” to “I monitor this name”:

Pattern A — watch mode. Re-scan periodically and surface diffs:

Terminal window
adler --watch torvalds # diff vs last cached run
adler --watch --interval 86400 torvalds # re-scan every 24h

The 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, confidence chips, identity clusters, report exports, and the access engine view, launch the bundled SPA:

Terminal window
adler --web
# http://127.0.0.1:8080

See the Web UI page for the full feature tour.


  • Adler’s three-verdict model and why Uncertain is information, not failure.
  • How to inspect signal evidence, confidence reasons, and profile evidence with --explain, --enrich, and --format ndjson.
  • That datacenter IPs cause most Uncertains and how to remedy them.
  • How to layer a residential proxy + browser backend.
  • How to export a case-level investigation report.
  • Two workflow patterns for tracking a name over time.
  • 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, identity clusters, and report exports.
  • Investigation reports — Markdown, JSON, HTML, Web API, and MCP case-file output.
  • Honest verdicts — the philosophy doc behind the three-verdict model.
  • FAQ — common edge cases and gotchas.
  • Glossary — terminology lookup.