A complete vehicle-identification system running as a single self-hosted workflow: a camera page in the browser, a vision model that names the car, a 170-vehicle inventory database, a public dashboard and a protected admin - no separate backend, no app, no cloud server. Built in one evening, and improved by one instructive failure.
There is nothing to install. A web page served by the workflow itself opens the phone's rear camera directly through <input capture="environment">. The photograph is resized to 1280px in a canvas on the device before upload - which cuts both transfer time on mobile data and the token cost of the vision call - then posted as base64 to a webhook. The response comes back as JSON and is rendered in the same page.

// the entry point: one button, opening the camera

// a real scan: Chery Tiggo 8 Pro, 95% confidence, five units found in stock with prices
{ } source
// 24 nodes across 5 entry points: the scanner page, the scan API, the public inventory dashboard, the admin page, and the guarded write endpoint · click to open the exported workflow - credentials and keys stripped, importable into any n8n instance
canvas.toDataURL('image/jpeg', 0.82).temperature: 0 for repeatable identification and a forced JSON contract so the response shape is never guesswork.The first version of the prompt asked the model to identify the car and return the make and model using the spellings from the catalog. A Chery Tiggo 8 - a brand common on local roads and absent from that catalog - came back as an MG HS at 95% confidence. Both wear a diamond-mesh grille, and a model handed a closed list is pulled toward it. The confidence score is the dangerous part: the system was not hesitating. It was wrong, and certain.
The generalisable rule: give a model a closed list and it will be drawn to it, even when the correct answer lies outside. The fix was not a better list - it was separating "what do you see?" from "which of these do we carry?", and explicitly authorising null as an answer. Once identification stopped competing with matching, both got better.
Two smaller changes shipped with it. temperature: 0, so the same photograph always produces the same identification. And recognition cues for the brands a Western-trained model tends to under-weight - Chery, Omoda, Jaecoo, Geely, Haval, BYD, MG, Skywell, Zeekr - written as visual tells (badge shape, grille pattern) rather than as a list of names. Twenty Chinese-market vehicles were added to the inventory at the same time, because a local dealership in 2026 without them is not a credible dataset.
Re-running the same photograph after the change returned Chery Tiggo 8 Pro at 95%, with the model citing the oval badge, the diamond-mesh grille and the connected rear lamps - and five matching units in stock.
The stock is managed from a single page: live statistics, client-side free-text search across every field, and an embedded QR code that opens the scanner on a phone - so during a demonstration the audience can scan the screen and try it themselves. The admin variant adds a form to add a vehicle and a delete control on each row. Both hit one authenticated endpoint that routes between insert and delete, with the key checked server-side and a 403 returned without it.

// the public dashboard - read-only, with the QR that opens the scanner

// the admin view: add and remove stock, reachable only with the key