What Changed Since Tuesday: Recon as a Longitudinal Job
A one-shot scan answers the wrong question. The finding that matters is not which subdomains exist, it is which one appeared last week. That requires storing scans, and getting one field exactly right.
What Changed Since Tuesday: Recon as a Longitudinal Job
TL;DR: "Which subdomains does this domain have" is a less useful question than "which one appeared since last week." Answering the second requires storing every scan and comparing them, and the hard part is not storage. It is giving each finding an identity stable enough that an unchanged reality produces an empty diff. That is what the Recon Workspace does.
Run a subdomain scan today and you get a list. Run it again next month and you get a slightly different list, and now you are diffing two text files by eye, hoping you still have the first one.
That workflow is backwards, because the interesting event is almost never in the list itself. It is in the delta. staging-api.example.com existing is unremarkable. staging-api.example.com appearing three days ago, when it was not there before, is a lead.
The single-shot tool problem
Every tool on this site is deliberately stateless. You open it, paste something, get an answer, and leave. Nothing is stored, which is the entire privacy argument, and for formatting JSON it is exactly right.
For reconnaissance it is a real limitation. We checked our own privacy tools while building the workspace: not one of them stored a single byte between page loads. Every scan result died on refresh. If you wanted history you kept it yourself, in a scratch file, and compared by hand.
So the workspace is not a nicer frame around the same tools. If it were, it would be worse than the tool pages it duplicates. The only thing it adds is memory, and memory is the whole product.
Stable identity is the hard part
Here is the problem that decides whether any of this works.
To diff two scans you need to know that a finding in scan B is the same finding as one in scan A. That means every finding needs an identifier that survives from one run to the next. Get it wrong and every re-run reports that everything is new and everything was deleted, which is worse than having no diff at all, because now you have noise that looks like signal.
The rule we settled on: an identifier must never contain a value that can change while the thing stays the same.
A subdomain is keyed by its fully qualified name, subdomain:api.example.com, and specifically not by its IP address. If api.example.com moves from one host to another, that is a change to an existing finding, not the disappearance of one finding and the birth of another. The key holds; the evidence attached to it differs, and the diff reports "changed" rather than "added and removed."
DNS findings are keyed by an internal check code, dns:SPF_MISSING, rather than by the message shown on screen. That way rewording a description never makes a re-audit look like the domain changed. Prose is for humans and moves freely; identity is structural and does not.
Username findings key on platform plus handle, username:github:torvalds, so the same handle on two platforms is two findings, which is what you want when one of them disappears.
We have a test asserting that two scans over unchanged data produce an empty diff. It sounds trivial. It is the property the entire feature rests on.
Two failure modes worth designing around
A stopped sweep must keep what it found. Enumerating a real wordlist takes a while, and people stop scans. Findings are written as they arrive rather than batched at the end, so a sweep you abort at 60% leaves you holding 60% of the results, all of it saved.
An aborted run makes a terrible baseline. This one is subtle and worth stating. If you stop a scan halfway and the next diff compares against it, every prefix you never got to looks like it vanished. So the comparison only ever considers completed runs. A partial scan is visible in your history, and is deliberately not used as a reference point.
There is also a smaller honesty problem in the same family. A username check that hits a rate limit is not evidence the account is absent. Recording it as "not found" would make the next diff announce that a profile disappeared, when all that happened was an HTTP 403. Inconclusive results are stored as inconclusive, or not at all.
Pivots are suggested, never automatic
Scanning a domain surfaces things worth following. The nameservers and mail exchangers in a DNS answer often name the operating organization, which is a reasonable next thread to pull.
The workspace surfaces those as suggestions with a single click to accept. It does not add them and start scanning, and that is a considered choice rather than an unfinished feature. Turning "I looked up a domain" into "I began enumerating a person" should be a decision someone makes on purpose, not a side effect of a checkbox.
Privacy Note: Targets, scan history and findings are stored in IndexedDB on your own device. DNS queries go to public resolvers and username checks to each platform's public API, straight from your browser. There is no Utilora server in the path and no account to create, which also means clearing site data deletes your history. Export a report before you do.
When a snapshot is the right tool
If you want one answer right now, use the single-shot tools. DNS and mail security, subdomain enumeration, username sweeps: no setup, nothing saved, gone when you close the tab.
Use the workspace when the question has a "since" in it.
Try these tools
Scan for active subdomains entirely in your browser using secure DNS-over-HTTPS. Protect your investigation targets from logging.
Analyze DNS records (MX, SPF, DMARC, TXT) to identify email spoofing risks and domain security configurations privately in your browser.
Search for profiles associated with a username across developer and tech platforms. Runs 100% locally in your browser for absolute privacy.