# trackerjacker: the last release is from 2018 and the sample map reports +4 dBm

> This tool maps nearby WiFi networks and the devices on them by putting an interface into raw 802.11 monitor mode. Its packaging has two small defects worth knowing about, its example map contains signal values that are not physically possible, and its own list of use cases includes knocking other people's devices off a network, which is a scope question the tool never addresses.

**calebmadrigal/trackerjacker** — Like nmap for mapping wifi networks you're not connected to, plus device tracking

- Repository: https://github.com/calebmadrigal/trackerjacker
- Stars: 2,742 · Forks: 192
- Language: Python
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/calebmadrigal-trackerjacker

## The newest release is from 2018 and the newest commit is from 2026

The release history has two entries and both are old. v1.7.9 was published on 2018-04-28 with the note that it moved to scapy core, and v1.8.0 followed on 2018-04-30 with the note that it added basic macOS support. Nothing has been tagged since. The last push to the default branch is dated 2026-03-22, so commits have continued for years after the last release without a new tag. The practical effect is that the two versions move independently: the source you get from a clone is not the code that produced 1.8.0, and nothing in the repository states which dependency set the current source expects beyond the requirements file. The last release note and the README agree on the macOS story at least, since the README still calls macOS pre-alpha rather than claiming the support that release introduced.

## The install requirements are read line by line, so blank lines become empty requirements

The dependency list is not written where you would expect it. setup.py does not list dependencies inline. It opens requirements.txt and splits the whole file on line boundaries:

```
with open('requirements.txt', 'r') as f:
    requirements = f.read().splitlines()
```

and then passes that list straight through as install_requires. The file it reads holds three entries:

```
scapy>=2.5.0
pyaml>=17.12.1
ruamel.yaml>=0.15.35
```

Splitting on line boundaries does not discard blank lines, it keeps them as empty strings. The requirements file as it sits in the repository ends with blank lines after the third entry, which means the list handed to the installer contains two empty strings alongside the three real requirements. A comment line would behave the same way. The fix is to filter, and the absence of a filter is the defect. Note also that two separate YAML libraries are pulled in for one YAML file, with pyaml and ruamel.yaml both required at runtime rather than one being optional.

## The long description is converted to reStructuredText and then declared as markdown

The packaging file tries to be helpful about the README and gets the format wrong in the process. There is a helper that attempts to convert README.md, and if pypandoc or its input is unavailable it falls back to reading the file as plain text:

```
def get_readme():
    try:
        import pypandoc
        readme_data = pypandoc.convert_file('README.md', 'rst')
    except(IOError, ImportError):
        readme_data = open('README.md').read()
    return readme_data
```

The conversion target is rst, which produces a restructured text document. Three lines later the setup call declares long_description_content_type as markdown. So on a machine with pypandoc installed the package index is handed restructured text and told it is markdown, and on a machine without it the raw markdown is handed over and still told it is markdown. One of those two paths has to render incorrectly, and the declared type matches only the fallback. The version number is read the same way, by executing trackerjacker/version.py and pulling one name out of the resulting namespace.

## The example map reports signal strengths of +1 and +4 dBm

The sample wifi_map.yaml in the README is the most useful thing in the documentation, and it contains values that cannot be true. A signal field measured in dBm should never be positive, and the sample mixes plausible negatives such as -86, -52, -46 and -80 with entries reading 1 and 4. Several devices and two access points carry a value of 4, and one carries 1. The curses display from the foxhunt plugin in the same file is consistent and correct, showing -82dBm through -88dBm and never a positive number. So the two outputs disagree about what the field means, and the positive values appear only in the YAML path. That matters beyond tidiness, because one of the stated use cases is to be alerted when a MAC address is seen above -40dBm, and a value of 1 or 4 would satisfy that threshold trivially. Either the field is not dBm in that path, or the values are being computed wrong.

## Two addresses in the sample map sit in the block phones use to randomize

The sample map illustrates the limitation of doing device tracking by MAC address, and does it accidentally. Among the devices listed there are two addresses beginning 01: one is 01:00:5e:96:e1:89 and the other is 01:80:c2:62:9e:36. The 01 prefix is the range reserved for locally administered addresses, and it is what modern phones put on the air when they randomise their hardware address per network. Neither of those two entries has a vendor, and neither does a third address in the map. So the output the tool is best known for is, for exactly the devices most people care about tracking, both unattributable and unidentifiable, and it looks the same as an unknown vendor that simply failed to resolve. The map also shows hidden networks, with two access points carrying an ssid of null, and one network name appearing twice under two different access points at very different signal levels.

## The documented plugin path does not exist in the repository layout

The custom plugin example invokes a file by a path that the top level of the repository does not contain. The command shown is of the form trigger-plugin followed by examples/plugin_example1.py, with a trigger cooldown flag set to 1. The repository root holds a directory named plugin_examples, and there is no examples directory at the top level. So the path a reader is told to copy does not match the layout, and the entry point to write your own plugin has to be found by browsing rather than by following the documentation. The same section does make one thing clear: foxhunt is a built-in plugin, and you can define your own against the same plugin interface. The built-in one is passive, displaying power, device id and vendor for nearby devices on a curses screen.

## Two sections of the README share one heading

The usage part of the README has a repeated section title. There is a heading for a track mode example with the foxhunt plugin, and further down another heading with exactly the same wording for the custom plugin example. They document different things, so a table of contents built from those headings lists the same entry twice and one of the two examples is unreachable from it. It is a small thing, but it is the kind of duplication that survives in a file whose most recent release predates the current source. The structure around it is sound: a usage section points at the tool's own help output, then splits into map mode and track mode, and the map mode example shows the interface flag and the map flag together producing wifi_map.yaml by default, with the README noting that because the output is YAML it can be fed straight into your own scripts.

## The use case list includes deauthenticating other people's devices

This is the part to read before running the tool anywhere. The README lists what it can help with, and among the alerting ideas, which run a command when a device crosses a byte threshold, are two that describe deauthenticating devices. One is about deauthenticating anything that exceeds a byte threshold in a ten second window. The other says plainly: deauthenticate every camera of a particular brand in the area so that hosts do not spy on the author. Disconnecting hardware you do not own, on a network you are not on, is interference with someone else's equipment and on many frequencies it is a regulatory matter as well as an unpleasant one. The tool has no authorisation boundary, no dry run and no per-target limit. It sees every network in radio range, including the ones you have no relationship with, and the trigger mechanism will run whatever command you hand it.

## Conclusion

Treat trackerjacker as a passive survey tool for networks you are authorised to look at, and expect it to be an older codebase: the newest release predates the last commit by years, the sample output has a data quality defect, and the install path has an empty-entry bug in it. Two things to settle before running it. You need a wireless interface in monitor mode, and macOS is marked pre-alpha. And the tool carries no notion of whose devices you are watching, so if you point it at a building you have no relationship with, everything it lists is somebody else's hardware and nothing in its design will stop you from acting on that.

## FAQ

### What does trackerjacker do?

It maps and tracks WiFi networks and the devices on them through raw 802.11 monitoring. It has two usage modes, map and track, and by default map mode writes a file named wifi_map.yaml listing every nearby network with its access points, byte counts and associated devices.

### What does trackerjacker need in order to run?

An interface in monitor mode, since it works by raw 802.11 monitoring. The supported platforms are given as Linux, tested on Ubuntu, Kali and a Raspberry Pi, and macOS, which is marked pre-alpha. It installs with pip3 install trackerjacker.

### How does trackerjacker decide a device vendor?

From the MAC address prefix. Two addresses in the example map begin with 01, the block used for locally administered addresses that phones use when randomising, and neither carries a vendor field, so randomised devices cannot be attributed from the output.

### How current is trackerjacker?

The most recent releases are v1.7.9 on 2018-04-28, described as moving to scapy core, and v1.8.0 on 2018-04-30, described as basic macOS support. The last push to the master branch is dated 2026-03-22, so commits continued long after the last tag.

### Can trackerjacker measure how much data a device is sending?

Track mode counts bytes per MAC address and fires a trigger when a device exceeds a threshold, given on the command line. The README shows an example with a threshold of 4000 bytes, a trigger command and a list of channels to monitor.

## Sources

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

---

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