# webanalyze, Wappalyzer technology detection rebuilt in Go

> webanalyze is a Go port of Wappalyzer that fingerprints which technologies a site runs, built for scanning large host lists rather than for a single page. It ships the detection definitions as a JSON file, adds a crawl option and CSV and JSON output, and can be run as a library or from a container image.

**rverton/webanalyze** — Port of Wappalyzer (uncovers technologies used on websites) to automate mass scanning.

- Repository: https://github.com/rverton/webanalyze
- Stars: 1,188 · Forks: 158
- Language: Go
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/rverton-webanalyze

## Detection rules without the definition feed

webanalyze is a port of Wappalyzer in Go, and the README says the design goal directly, that it is designed to be performant and allows testing huge lists of hosts. The interesting wrinkle is where the rules come from. Wappalyzer removed public access to their app definitions, and the note in the README says that webanalyze therefore currently loads definitions from the enthec/webappanalyzer project. The rules live in a technologies.json file, which is present in the repository and is refreshed with the update flag. This is the part of the design that deserves scrutiny, because the detection quality of the tool is entirely a property of that file, and the file is maintained elsewhere. A fingerprint that stops matching, or a new technology that nobody has written a rule for, both look the same from the outside, a site with no detected stack.

## The flag set covers one host or a list of them

The usage section lists the whole interface, and it is a small one. The apps flag points at the definition file, which defaults to technologies.json. The host flag takes a single host to test and the hosts flag takes a filename with one host per line, which is how you run it against a list. The worker flag sets the number of workers and defaults to 4, which is the concurrency knob for a mass scan. The crawl flag sets how many links to follow from the root page and defaults to 0, so out of the box the tool looks at one page. The search flag defaults to true and searches all URLs with the same base domain, so example.com and sub.example.com are both covered. Output goes to stdout, csv or json, and the silent flag avoids printing the header block. The update flag refreshes the definitions file, and the header flag can be repeated to send custom request headers.

```shell
$ webanalyze -host example.com -header "User-Agent: Mozilla/5.0" -header "Authorization: Bearer token"
```

## What a run actually prints

The example output in the README shows the shape of the result, and it is worth reading because it shows what is inferred rather than confirmed. A run prints a configuration header with the version, the worker count, the apps file in use, the crawl count and whether subdomain search is on, and then a block per URL with the elapsed time and the detected technologies, each with its category in parentheses.

```shell
$ ./webanalyze -host robinverton.de -crawl 1
```

The detections include a version for some entries, such as Hugo, 0.42.1 under the Static Site Generator category, and no version for others. The version comes from whatever the fingerprint matched, which in practice means a header value or a path on the site, so it is evidence about the surface rather than a statement from the software itself. The CSV output flattens the same data with the columns Host, Category, App and Version, which is the format you would actually want to feed into a report, and the JSON output is there for the same reason.

## Small dependencies, and the library entry point

The go.mod is short, which is what a focused tool looks like. The module is github.com/rverton/webanalyze and it declares go 1.27.1, with two direct dependencies, PuerkitoBio/goquery for parsing HTML and bobesa/go-domain-util for the base domain work that the subdomain search option depends on, and golang.org/x/net and golang.org/x/text underneath. The development section of the README points at cmd/webanalyze/main.go as the example of using it as a library, so the detection logic is meant to be called from your own Go program rather than only from the command line. The repository layout is correspondingly flat, with the main source in webanalyze.go, the Wappalyzer detection logic in wappalyze.go, the job description in jobdesc.go, the tests, and cmd/ for the command.

## A two stage image that ships the definitions

The Dockerfile is compact and does one thing beyond a normal build, which is that it downloads the definitions at image build time. The build stage uses golang:1.27.1-alpine, downloads the modules, and compiles a static binary with CGO_ENABLED=0 and the trimpath flag. The runtime stage is alpine:latest with the ca-certificates package, a non-root user created with adduser and the working directory chowned to it, the binary copied in and the user switched before the definitions are fetched.

```bash
git clone https://github.com/rverton/webanalyze.git
docker build -t webanalyze:latest webanalyze
docker run -it webanalyze:latest -h
```

The RUN step that calls the update flag before the entrypoint is set means the image ships with a technologies.json fetched at build time, which is convenient, and it also means that image has a definition file frozen at its build date unless it is rebuilt.

## What detection does and does not tell you

The honest limitation is inherent to the technique rather than to this implementation. A fingerprint is a rule that matches something observable in a response, so the tool reports what a site exposes, not what it runs. A server header, a cookie, a script path or a comment in the markup is what produces a result, and a determined administrator can remove all of them. That cuts both ways, since a site running Hugo 0.42.1 does not have to announce it, and a site that does announce it may be running something else behind a proxy. The crawl option extends the fingerprinting to linked pages, which finds subdomains and other hosts that the root page does not link to, but it also means the tool reaches further into a target than a single request would. The mass scanning use case, which is the point of the workers flag, is the one that most needs a written authorisation scope, and the tool itself has no mechanism for one, since it takes a list of hosts and reports what it finds.

## A small project with a fast release cadence

The repository is not archived and the last push was on 2026-09-19, and the release tags are dense in the same period, with v0.4.4 on 2026-08-27, v0.4.5 on 2026-08-28 and v0.4.6 on 2026-09-19. The version numbering in the 0.4 range matches the pre 1.0 convention, which usually means the interface is still moving, so a consumer that depends on it should pin a version rather than track the branch. The licence is MIT, in the LICENSE file at the root, which is the permissive grant you want for a tool you run inside your own reconnaissance pipeline. The release binaries are produced with a .goreleaser.yaml in the tree, so the precompiled releases cover the usual set of platforms, and the README points at the releases page for those rather than asking everyone to build from source. Building from source is one go install command away.

```shell
$ go install -v github.com/rverton/webanalyze/cmd/webanalyze@latest
```

## Conclusion

webanalyze fits a security engineer doing authorised reconnaissance, who needs to know what stack a list of hosts runs before deciding what to test next, and it fits a Go team that wants the detection logic inside their own tooling rather than as a separate binary. It does not fit anyone who wants to verify a technology version rather than infer it, since detection is a set of fingerprints matched against responses, and it does not fit a workflow that assumes the definitions are always current, because the definition file comes from a third party project. Verify three things first: that your use is authorised for the hosts you scan, that the technologies.json file on your machine matches the fingerprints your targets would produce, and whether the version strings it reports are the kind of evidence you need, since a detected version comes from a header or a script path rather than from the target confirming it.

## FAQ

### What is webanalyze?

It is a port of Wappalyzer in Go, designed to be performant and to allow testing huge lists of hosts. It fingerprints which technologies a site runs and reports them with their category, and optionally the version when the fingerprint exposes one.

### Where does webanalyze get its technology definitions?

Since Wappalyzer removed public access to their app definitions, webanalyze loads definitions from the enthec/webappanalyzer project. The definitions live in a technologies.json file, which is shipped in the repository and refreshed with the update flag, which downloads a current version from that project.

### How do I scan a list of hosts with webanalyze?

Use the hosts flag with a filename containing one host per line, and set the worker flag to the concurrency you want, which defaults to 4. The output flag selects stdout, csv or json, and the search flag, on by default, covers all URLs sharing the same base domain.

### Can webanalyze be used as a Go library?

Yes. The README points at cmd/webanalyze/main.go as an example of using it as a library. The module is github.com/rverton/webanalyze, and it declares go 1.27.1 with goquery for HTML parsing and go-domain-util for the base domain handling.

## Sources

- [Issues](https://github.com/rverton/webanalyze/issues)
- [License: MIT](https://github.com/rverton/webanalyze/blob/master/LICENSE)
- [README](https://github.com/rverton/webanalyze/blob/master/README.md)
- [Releases](https://github.com/rverton/webanalyze/releases)
- [rverton/webanalyze on GitHub](https://github.com/rverton/webanalyze)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rverton-webanalyze
