Products // our product

Data Collector

Configurable platform for collecting and reviewing field data.

Every computer-vision project needs field data before a model can learn anything. Data Collector is the app that gathers it: describe your scenario as a config, hand field workers the phone, and start collecting, with no new data pipeline to build for each project.

Language Dart · Python

The problem

Describe the scenario

Every new way of collecting data used to start the same way: someone wrote a fresh pipeline for it. In the field, photos and notes ended up in messengers and spreadsheets, and there was no single place to see what had been gathered or what to do with it.

Data Collector turns the scenario itself into the input. In the admin an administrator describes what to collect as a set of fields, text, date, a photo, an instruction block, and arranges them into a screen order. One set of fields is one form screen, and the order of screens is the scenario.

That config is plain JSON, and it lives in a Git repository: one repository per project, the config at a fixed path next to the project's instruction media. Adding a scenario, or changing one, is a commit to that JSON, so the app itself ships nothing new: it just pulls the latest config.

How it works

Collect in the field

A field worker signs in to the mobile app and sees the projects they have been given access to. The app downloads the current config from the server and caches it locally, so the work runs offline.

Guided by the scenario, the worker fills the form and attaches photos screen by screen. The camera step shows a reference angle and runs a quick quality check on the shot, right on the phone: it measures sharpness and exposure, so a blurry or badly lit frame gets flagged with a prompt to retake. Each photo carries its own camera metadata, the lens intrinsics and EXIF, because the models downstream need it to measure anything from the image.

On submit the app bundles everything into one package: a JSON manifest plus the photo files, kept separate so nothing bloats the JSON. The package then waits on the device. The worker chooses when to upload it from the Server tab, so nothing goes out until they press send. The send itself is built to survive a weak connection: the files go up one at a time, then the manifest, then a commit. If the connection drops, it resumes from the next unsent file, and the whole package never restarts from the top.

Stack

Flutter (Android, iOS, Web client)Riverpod and Drift (offline state and local store)Django (mobile API and web admin)SQLAlchemy and fsspec (per-project data and blob storage)Git (config, media and visualization per project)Firebase AuthenticationPostgreSQL, S3 or GCS (production storage)

What you get

Review the data

Accepted packages show up in the admin, listed by project and filterable by the same fields that defined the form. Each package opens to its media files and a manifest, the JSON written once the upload completes.

Reception runs in phases, so the state of every submission is visible: waiting for files, ready to commit, completed, or failed. Two roles share the panel: staff with full access to create and edit any project, and a client-admin role limited to viewing the projects it has been granted.

There is one more layer for projects that run a model. Data Collector does not run the model itself: you bring your own. Point your pipeline at the project so it writes its results back in, then add a small visualization file that tells the admin how to draw them: keypoints, a depth map, detection boxes, or a link out to a labeling task. The admin overlays them on the photos, so the same place that collected the data also shows what the model made of it, the raw capture and the model's read side by side. For now those overlays live in the web admin only. The result is one place where the collected data, its media, and the model output sit together per project, with no manual gluing from messengers or spreadsheets.

Who built this

Want this on your stack?