# OpenDataCam: the install script is pinned to a 2021 tag, the default branch is not, and the ports are three

> OpenDataCam counts moving objects in camera feeds and videos with darknet and YOLOv4, served as a Next.js front end over three separate ports with a Mongo store. Its quick start downloads an installer from the v3.0.2 tag, which is where the newest release also sits, five years before the last push to the branch it is developed on.

**opendatacam/opendatacam** — An open source tool to quantify the world

- Repository: https://github.com/opendatacam/opendatacam
- Website: https://opendata.cam
- Stars: 1,728 · Forks: 299
- Language: JavaScript
- License: MIT
- Published: 2026-09-16 · Updated: 2026-09-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/opendatacam-opendatacam

## The installer comes from a 2021 tag while the branch has five more years

The documented install fetches one file, and the URL names a tag:

```bash
# Download install script
wget -N https://raw.githubusercontent.com/opendatacam/opendatacam/v3.0.2/docker/install-opendatacam.sh

# Give exec permission
chmod 777 install-opendatacam.sh
```

That `v3.0.2` is also the newest published release, dated 2021-09-16, with two prereleases before it, `v3.0.2-beta.1` and `v3.0.2-beta.2`, on 2021-08-27 and the same day in September. The last recorded push to the repository is 2026-04-23, and the default branch is `development` rather than `main`. So three code sources exist and they do not agree: the default branch, the package manifest which declares version 3.0.2, and the tag the installer actually pulls.

A quick start that follows the page installs five year old code, and the documentation that surrounds it is written against that vintage. The prerequisites name Nvidia CUDA 11 and cuDNN 8, plus the Nvidia container toolkit and a separately installed `nvidia-container-runtime`, and Jetpack 5.x for a Jetson device. Jetpack 5 arrived years after the tag those requirements sit next to.

The three documented platform flags are `--platform nano` for a Jetson Nano, `--platform xavier` for Xavier and Xavier NX, and `--platform desktop` for a laptop, desktop or server with an NVIDIA GPU.

## chmod 777 on the file that then asks for a sudo password

Two instructions in the same block are worth reading together. The script is fetched with `wget -N`, which asks the server for a timestamp and re-downloads when it differs, and it is then made world readable, writable and executable with `chmod 777`. The page also notes that you will be asked for a sudo password when installing.

So the file is granted every permission bit on a machine, and the first thing it does is ask for root. The permission is broader than the script needs, and it persists on disk after the install completes, in whatever directory you ran it from. If that directory is a shared or synced one, the file travels.

The stop instruction has the same coupling. To stop the container you run `docker-compose down` in the same folder as the install script, which means the lifecycle of the deployment is owned by the directory a downloaded file happens to sit in. Deleting or moving that folder does not stop anything, and copying it to another machine carries a control surface with it.

The container itself starts in auto-restart mode, so a reboot brings OpenDataCam back up on its own. That is convenient at a roadside cabinet and worth knowing about before you try to take a machine offline for maintenance.

## Three ports ship in the example environment file and one is written down

The example environment file is four lines:

```bash
PORT_APP=8080
PORT_DARKNET_MJPEG_STREAM=8090
PORT_DARKNET_JSON_STREAM=8070
MONGODB_URL=mongodb://mongo:27017
```

Three HTTP ports and one database service. The page tells you about 8080 and nothing else: after the install you open `http://[IP_OF_JETSON]:8080` and start counting on a demo video of a busy intersection.

The other two names are self describing. One carries MJPEG frames for a detector running on a GPU, which is how a live camera preview reaches the browser without being a video codec. The other carries JSON over the same path for the structured detections and tracking output. So a live deployment is not one web app on one port, it is a UI plus a frame feed plus a data feed, on 8080, 8090 and 8070.

The database is addressed as the host `mongo` on its default port, which is the Docker Compose service name rather than a hostname on your network. Anyone putting this behind a firewall needs to decide about all three ports and not only the one named in the quick start, and the MJPEG and JSON ports are the two that carry continuous traffic rather than a request and a response.

## The detector's standard output is what the browser log shows

The dependency list explains how the console output reaches the page. `intercept-stdout` appears alongside `server-sent-events` and `react-lazylog`, and that is a complete chain rather than three unrelated packages. The detector process writes to standard output, `intercept-stdout` captures it inside the Node server, `server-sent-events` pushes those lines to the browser, and `react-lazylog` renders them as a scrolling terminal in the page.

Two other dependencies close the loop on process control. `forever-monitor` is a supervisor, and `killable` and `splitargs` are what let the server stop that supervised child cleanly. So the container is not one process, it is a Node application supervising a detector it can restart and terminate, with the child's console piped into the interface.

That has an operational consequence worth stating. Whatever the detector prints is being broadcast to every connected browser, because the interface is built to show it. Progress lines are the point, but so is anything the underlying stack writes to the same stream, and the choice to display the raw stream rather than a filtered view is what makes the feature work at all. There is no separation between a user facing log and a diagnostic one here.

The API is documented as the alternative to forking the project, with separate pages for counter data and tracker data, and a `csv-express` dependency behind the export.

## Next 10 with React 16, and a dependency pinned to a release candidate

The frontend stack is stated in full in the manifest, and it is the generation that matches the 2021 release rather than anything later.

`next` is at `^10.2.3`, with `react` and `react-dom` both at `^16.13.1`. State is Redux `^4.0.5` with `redux-thunk` `^2.3.0` and `next-redux-wrapper` `^5.0.0`, the last of which is server side rendering support, so the Next app is not purely client rendered. Styling is a mix of `styled-jsx` `^4.0.1`, `react-inlinesvg` `^1.2.0`, a `tailwind.config.js` and a `postcss.config.js`, with `autoprefixer` `^9.8.0` and `cssnano` `^4.1.10` in dev dependencies.

One entry is worth stopping on. `immutable` is declared as `^4.0.0-rc.12`, a release candidate, with a caret range on a prerelease. A prerelease as the declared baseline of a caret range is a decision about what the range will and will not pick up, and it is the kind of line that reads as a leftover rather than a policy.

The tracking and detection dependencies sit outside this repository. `node-moving-things-tracker` `^0.9.1` handles the trajectories, `point-in-polygon` `^1.0.1` is what the counter lines use, and `node-gpsd` `^0.3.2` reads NMEA data. The acknowledgements name darknet, a YOLOv4 fork of it, and an IOU and V-IOU tracker, which is the 2020 detector line, consistent with the 50 or more object classes the page advertises out of the box and the option to supply custom neural network weights in the configuration.

## Development and production are the same shell script with a different NODE_ENV

Six npm scripts, and five of them delegate to shell scripts in `scripts/npm`:

```json
"dev": "scripts/npm/startServer.sh",
"lint": "scripts/npm/lint.sh",
"build": "scripts/npm/build.sh",
"start": "NODE_ENV=production scripts/npm/startServer.sh",
"generateapidoc": "scripts/npm/generateapidoc.sh",
"test": "scripts/npm/test.sh"
```

`dev` and `start` call the same file, `startServer.sh`, and differ only by an environment variable set inline. That keeps one entry point, which is the point, and it also means the behaviour difference between a development run and a production run is whatever that one variable changes rather than anything visible in the script definitions.

Tests and linting are behind shell scripts too, so `npm test` does not obviously mean a JavaScript test runner. The API documentation is generated by `generateapidoc.sh` against an `apidoc.json` at the root, with `apidoc` `^0.50.4` in dev dependencies, and the output is what gets published at the project's GitHub Pages address under `apidoc/`, with anchors for the counter data and tracker data endpoints. So the public API reference is a build product of this repository rather than something maintained by hand.

Linting is `eslint` `^7.15.0` with `eslint-config-airbnb` `^18.2.1` and an `.eslintrc.json` at the root. Those pins belong to the same 2021 window as the React and Next versions.

## MongoDB driver 3 and the retired request library sit in runtime dependencies

Two entries in `dependencies` describe where this project sits in time better than the release date does.

`mongodb` is `^3.5.8`. That is the 3.x generation of the Node driver, and the environment file points it at a service named `mongo` with no authentication in the connection string, which is the shape that predates the current default of requiring credentials.

`request` is `^2.88.2`. It is the library Node deprecated in long favour of the built in fetch, and it is present in runtime dependencies rather than dev dependencies, meaning something on the request path is using it. `axios` `^0.21.1` is in the same list, so both HTTP clients are installed.

Other pins are exact rather than ranged: `color-string` at `1.5.3`, `dotenv` at `8.2.0` and `splitargs` at `0.0.7`. A three digit patch level as a hard pin is a deliberate hold, and `0.0.7` is a very early version for a package that parses command lines.

None of this is a defect on its own. It is the profile of a project whose dependency set was settled around the 3.0.2 tag and whose manifest has not moved since, which is the same fact the tag pinned installer reports from a different direction.

## Two configuration files at the root, and no Dockerfile in it

The top level carries twenty six entries. Configuration is split between two of them and neither is named in the quick start.

`config.json` sits at the root and is where the application settings live. The page points at a configuration document for the video input setting, which is how you switch from the bundled demo to a USB camera, and for custom neural network weights, which is how you replace the bundled detector. `.env.example` sits beside it and holds the four lines of ports and the Mongo URL. So one file changes behaviour and the other changes wiring, and the page never says which is which or which takes precedence when they disagree.

There is no Dockerfile at the root. The `docker/` directory holds the container definition and the installer the quick start fetches, and the tag in that URL is `v3.0.2`. The rest of the listing is application code: `components/`, `pages/`, `styles/`, `utils/`, `server/` alongside a `server.js` entry file, `statemanagement/` for the Redux store, `spec/` for tests, `scripts/`, and `public/`. Plus `package-lock.json`, `CODE_OF_CONDUCT.md`, `LICENSE` and `.eslintrc.json`.

The page is also written with the older Compose command line throughout. The prerequisite is Docker and Docker-Compose, and the stop instruction is `docker-compose down` with a hyphen, rather than the plugin form `docker compose`.

## Conclusion

OpenDataCam is worth looking at if you are counting traffic or objects at the roadside, on hardware you own, and the appeal is specific: a MIT licensed stack, no vendor, three ports to firewall, a live frame feed and a structured detection feed you can consume through an API rather than by forking the project. Check the code vintage before you plan around it. The newest release is 3.0.2 from 2021-09-16, the quick start installs from that tag, and the last push to the default branch is 2026-04-23, so the branch and the tag are not the same thing and the page has not moved with either. If you need the detector and the tracker to sit on current libraries, that is your own work. Plan for three listening ports rather than one, and remember the MJPEG and JSON feeds carry continuous traffic. Run the installer from a directory you control, give it narrower permissions than the documented 777, and do not treat the sudo prompt as incidental. The state of the deployment lives in whatever folder you downloaded it into, and the container restarts itself after a reboot. The bundled detector is darknet with a YOLOv4 fork and an IOU tracker, so count your accuracy expectations against 2020 models, and use the custom weights setting if that is not enough. Questions and bug reports are tracked in the project's Discussions and Issues rather than in this article.

## FAQ

### What does OpenDataCam detect out of the box?

The page states it detects 50 or more common objects without any training, and it is especially used for traffic studies such as modal split and turn counts. The bundled detector is darknet with a YOLOv4 fork, and the configuration exposes a setting for custom neural network weights when you need your own model.

### How do I install OpenDataCam?

Fetch the installer from the v3.0.2 tag with wget, make it executable, and run it with the platform flag for your hardware: nano for a Jetson Nano, xavier for Xavier or Xavier NX, desktop for a machine with an NVIDIA GPU. It downloads and starts a Docker container whose web server listens on port 8080. Docker and Docker-Compose are prerequisites, and a GPU host also needs CUDA 11, cuDNN 8, the Nvidia container toolkit and nvidia-container-runtime.

### Which ports does OpenDataCam use?

Three. The example environment file sets PORT_APP to 8080, PORT_DARKNET_MJPEG_STREAM to 8090 and PORT_DARKNET_JSON_STREAM to 8070, plus a MONGODB_URL pointing at a service named mongo. Only 8080 is mentioned in the quick start.

### Is OpenDataCam open source and what licence is it under?

It is distributed under the MIT licence, declared in the package manifest as the string MIT license with a LICENSE file at the repository root. The page also lists owning the data as one of its features and separates business and professional enquiries onto their own page.

### Can OpenDataCam count objects from a live camera rather than a video file?

Yes. The configuration document covers changing the video input to a USB camera or other cameras, and the page lists real-time or pre-recorded video sources as a feature. You can also drag a video file into the browser window to have it analysed instead.

## Sources

- [License: MIT](https://github.com/opendatacam/opendatacam/blob/development/LICENSE)
- [opendatacam/opendatacam on GitHub](https://github.com/opendatacam/opendatacam)
- [Project website](https://opendata.cam)
- [README](https://github.com/opendatacam/opendatacam/blob/development/README.md)
- [Releases](https://github.com/opendatacam/opendatacam/releases)

---

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