Getting connected
A K+DCAN cable and a desktop browser with Web Serial.
Before you plug anything in
Put the ignition in position 2 with the engine off, and make sure the battery is healthy. Most "the ECU rejected the request" errors are really a car that is not in the right state, or a battery sagging under load.
Any desktop, with a USB cable in the browser
The web app drives a K+DCAN cable through Web Serial, which only Chrome and Edge on the desktop implement. Safari has no Web Serial at all, so on a Mac with a USB cable use Chrome or Edge.
- Plug the cable in directlyInto the car's OBD-II port and into the machine. Avoid USB hubs.
- Click the cable chip in the top barThe chip is the connect control. Web Serial refuses to open its port picker unless a click asks for it, so the first connect is always yours.
- Choose your portOn macOS it starts with cu.usbserial, cu.usbmodem, cu.SLAB or cu.wchusbserial. On Linux, ttyUSB or ttyACM. The browser remembers the choice, and from then on the app reopens the cable on every load with no picker.
On iPhone, open it in a browser
Opening the app from the Files app preview will hang on the splash screen with no error. Quick Look restricts scripts. Open it in Safari, or add it to the home screen and launch it from there.
The cable
One is supported. An ELM327 is not it.
K+DCAN USB cable
The standard BMW cable. The app opens it at 115200 8N1 by default
and reopens the port at a different speed when a module needs one: DS2 and
KWP2000 modules run at 9600 8E1, BMW-FAST and D-CAN at
115200 8N1. You do not have to configure any of this.
If your cable uses an FTDI chip, its latency timer should be set to 1 ms.
The app does not change this setting for you; it only tells you when the symptoms
look like a slow timer. On macOS the FTDI driver's default can be high enough
that the cable misses its own echo, which surfaces as
IFH-0003.
Where it works
| Platform | K+DCAN USB |
|---|---|
| Chrome or Edge, desktop | Yes, via Web Serial |
| Safari | No, Safari has no Web Serial |
| iPhone and Android | No USB path on a phone; everything offline still works |
What you can do
Every module screen is BMW's own INPA screen, decompiled and rendered as it was drawn. Modules BMW never drew a screen for say so rather than guessing at a layout.
Fault memory
Read stored codes with their English text and detail, then clear them.
Whole-car scan
INPA's own vehicle script reads every module's fault memory in one pass; the result is a report joined with the fault lookup, printable.
Live values
Watch measurements update continuously as gauges, several at once, and log them to CSV with timestamps.
Activations
Drive real components for testing. Held actuators are released when you leave the screen.
Coding
Read and inspect coding data, stage changes, and see exactly what would be sent.
Trouble codes and plans
Search 51,484 fault codes offline, with P-codes and the matching ISTA service documents.
Wiring diagrams
BMW's WDS diagrams as vectors. Scroll to zoom, drag to pan.
Parts catalogue
ETK part numbers, diagrams, supersessions and VIN decoding.
Tool32
Run any SGBD job directly and read the raw result registers.
Tuning
Inspect ECU firmware images with a hex editor and TunerPro .xdf constants, flags and tables.
There is also a built-in tutorial: a seven step tour of the interface and five slides on how the whole thing works, from the Apps hub.
Supported cars
26 chassis for diagnostics. The parts catalogue reaches much further than that.
Diagnostics
Coverage per chassis varies with how many modules the car has: an E65 carries 96 module definitions, an E60 91, an E90 61, an E46 55, an F30 19.
Wiring diagrams
15 chassis: E38, E39, E46, E52, E53, E60, E63, E65, E70, E83, E85, E87, E89, E90 and F01.
Parts catalogue
246 chassis bundles, from the E3, E9, E12 and E21 through the current G series, plus the i models, the K series motorcycles and Rolls-Royce. This is far wider than the diagnostic coverage, because a parts lookup needs no live connection to the car.
Writing and safety
The short version: reading is open, and anything that changes the car asks first — and a refused write sends nothing at all.
Unknown jobs are treated as writes, and every write is gated
Every job is classified before it runs. Anything the classifier does not recognise is assumed to be a write, rather than assumed safe, and a blocked write is blocked before a single byte reaches the car, not caught partway through.
Actuator tests confirm before firing, are registered before they are sent, and are released when you leave the screen. A permanent write (an EEPROM change, a service reset) always confirms, whatever the setting. Coding writes take a backup first and re-read the module afterwards to prove what landed.
Coding
The coding editor stages changes and shows you exactly what would be sent, but it has no send path at all. That is deliberate rather than an oversight. A coding write is an EEPROM write, and on a module that gates the immobiliser or the airbags, getting it wrong means the car does not start, or worse. The send path does not exist rather than sitting behind a confirmation dialog that a stray keypress could clear.
Where a live coding write does exist, it takes a backup first, because once the write lands it cannot be undone, and it re-reads the module afterwards to prove the change actually took. A mismatch is reported as a verification error rather than a success.
Actuator tests
Activations drive real components, so confirmation is on by default. The dialog tells you which kind you are about to run:
- A test drive stays as set until you change it back or leave the screen.
- A permanent write changes the module for good and does not undo itself when you leave.
Leaving an activation screen releases anything still being held, so you cannot walk away from a running actuator by navigating elsewhere.
Working offline
The app installs to the home screen or the dock as a progressive web app and keeps working without a connection. Everything it reads is a static file, so once it is cached there is no server to be unreachable.
For a copy that never touches the network, every
release ships
self-contained builds: unzip one and open index.html. The
offline build (about 370 MB) has diagnostics, coding, the fault lookup
with its ISTA plans and the wiring diagrams; offline-no-wiring (about
220 MB) drops the diagrams. The offline-complete build adds the parts
catalogue for every chassis, which makes it about 6 GB, more than a GitHub
release asset may hold, so it lives on Hugging Face and is linked from each
release's notes.
Troubleshooting
The errors people actually hit, and what each one means.
No cable connected
Plug the cable directly into the machine rather than through a USB hub, and check the OBD-II end is fully seated.
Security access denied
Engine off, ignition in position 2, healthy battery. The security seed is random, so a retry sometimes succeeds where the first attempt did not.
The ECU rejected the request
Reported as conditions_not_correct. The module is refusing because
the car is not in the state the job requires. Ignition position 2, engine off.
The cable is not hearing itself
The K line is half duplex, so the cable should hear an echo of what it sends. When it does not, either the connection is loose, or the FTDI latency timer is too high. Reseat both ends first, then check the latency is 1 ms.
No response from the ECU
Nothing answered. Usually the module is not present on this car, is not powered in the current ignition position, or is on a bus this cable does not reach.
Damaged answer
Something replied, but the reply did not survive the wire. This is nearly always electrical: a marginal cable, a bad ground, or a low battery.
App error, not the car
When you see this, nothing needs checking on the vehicle. The fault is in the software, not the car.
Limitations
What this does not do yet, stated plainly.
- Flashing exists for backup only. Fault reading and clearing, live values, actuator tests (running INPA's own key scripts), guided test procedures and coding work; DME flashing stays read-side.
- ISO 9141 slow init is not implemented. Very early modules that need a 5 baud initialisation will refuse to connect rather than half work.
- A phone cannot use a USB cable, and a site served over HTTPS cannot talk to a car.
- If the wrong coding keyword table is matched, it returns plausible but wrong keywords rather than failing loudly. Treat unexpected coding readouts with suspicion.
- The macOS build is Apple Silicon.