The long version
The maintenance record for a car somebody actually owns.
Servicing, fuel, expenses, insurance, road tax and the roadworthiness test in one place, answering the two questions an owner really has: what is due next, and what has this vehicle cost me.
The category is full of expense trackers. This page is the case for why this one is not another, written so that every claim in it can be checked by opening the app rather than by taking anybody's word for it.
The facts first
- Platform
- iPhone. Not iPad, Mac, Apple Watch, Apple TV or Vision, and the app does not pretend otherwise: supportsTablet is off because every screen is laid out for one column at phone width.
- Languages
- Ten, all at launch. English (U.S., U.K., Australia), Portuguese (Portugal, Brazil), Spanish (Spain, Mexico), German, Italian, French.
- Live fuel prices
- Portugal, Spain, France, Italy and Austria, each from that country's own official source.
- Business model
- Free, with an optional subscription for the advanced views. No ads, no sponsored placements, nothing sold on.
- Data collection
- No analytics SDK, no advertising SDK, no IDFA, no tracking of any kind. Crash and performance diagnostics are not linked to identity.
- Works offline
- Completely. Not a degraded mode, the ordinary one.
- Built by
- One developer, in Portugal.
It knows where you live.
Ten locales, and they are not ten translations of one app. They are ten markets with their own words for the tax, the inspection and the insurance, and OdoKeep tracks the one that exists where the car is registered.
| Market | Annual tax | Roadworthiness test |
|---|---|---|
| Portugal | IUC | IPO |
| United Kingdom | VED | MOT |
| Germany | Kfz-Steuer | HU (TÜV) |
| Italy | bollo auto | revisione |
| Spain | IVTM | ITV |
| France | none since 2001 | contrôle technique |
| Brazil | IPVA | licenciamento anual |
| Mexico | tenencia, refrendo | verificación |
| Australia | rego | roadworthy, pink slip |
| United States | registration | state inspection |
France gets no annual car tax at all
Because France has not charged private cars one since 2001. An app that offers a French owner a field to fill in is an app that has translated a list rather than understood a market. The copy leans on the two pillars France does have.
Units are four decisions, not one
Distance, volume, consumption and tyre pressure move independently. The U.K. fills up in litres, counts miles, and reads consumption in miles per imperial gallon. Brazil and Mexico are metric but read consumption inverted, in km/L, where more is better. Tyre pressure is bar on the continent and psi in the anglophone markets.
The inspection cadence follows the car
Not the language. A vehicle's first test, and how often it repeats afterwards, is a function of its age, its type and its country, and the app schedules from that rather than asking the owner to know the rule.
VoiceOver speaks each language
Every string carries its own accessibilityLanguage, so a Portuguese vehicle note inside an English interface is read in a Portuguese voice instead of being sounded out as English. In an app whose content is written by its user, this is the difference between usable and unintelligible.
It derives instead of asking.
Every field an app demands is a reason to abandon it. Where OdoKeep can work something out from what the owner already wrote down, it does, and the thing it works out is never stored as a second source of truth that can drift.
Tyre sets
A set is never stored. It is computed from the records: write down that the winters went on in November and came off in April, and a tyre history exists, with the kilometres each set has run, without anyone having curated a list. Rename a set and the name attaches to the derivation, not to a row.
Service intervals
The app ships a maintenance taxonomy, but an owner's own history outranks it. Once there are two oil changes on a vehicle, the interval that matters is the one between them, in kilometres and in months, and that is what the next reminder is set from.
Cost of ownership
Marking an insurance premium or a tax payment as paid writes the expense too, so the total cost of a vehicle includes the paperwork rather than only the garage. Nobody has to remember to log the same money twice.
It puts open data where it belongs.
Five European countries publish what every filling station charges, updated daily, free to use. Nobody had put that beside the maintenance record it belongs next to. OdoKeep shows it on a map, in the same app that knows what the car drinks.
- Portugal
- DGEG
- Spain
- Geoportal de Gasolineras
- France
- data.economie.gouv.fr
- Italy
- Osservaprezzi, MIMIT
- Austria
- E-Control
The source is always named on screen
Every price says where it came from and when it was last updated. A number with no provenance is a rumour, and fuel prices are the kind of number people drive across town for.
The query is blurred before it leaves
Coordinates are rounded to three decimal places, roughly 100 metres, before the lookup is sent. The server needs the neighbourhood, not the driveway. The map itself is MapLibre over OpenFreeMap, so there is no third-party tile provider watching where anyone looks.
Only where there is data
The five covered markets are the only ones where any of this is mentioned. A reader in a country with no source is never promised prices near them, in the app, in the listing, or in the screenshots.
It is a tab, and it can be removed
Somebody who does not care about fuel prices can hide the tab entirely from Settings, and reorder the ones that are left. The feature does not get to occupy the navigation of a person who has said no to it.
A build requirement, not a pass at the end.
OdoKeep claims seven of the eight Accessibility Nutrition Label categories on iPhone. The eighth, captions and audio descriptions, does not apply: the app plays no audio and no video, and claiming it anyway would be the easiest lie on this page.
- VoiceOver
- Every screen navigable, every control labelled, and announcements on the screens that appear without being asked for.
- Voice Control
- Controls carry real accessibility frames, not hit slop, so the Show Names overlay lands on the box a person is aiming at.
- Larger Text
- The layout holds to the accessibility Dynamic Type sizes, numeric displays included.
- Sufficient Contrast
- Both palettes are built to the ratios rather than checked against them afterwards.
- Differentiate Without Color
- No state anywhere rests on hue alone.
- Reduced Motion
- Read live rather than sampled at launch, so turning it on reaches an app that is already running.
- Dark Interface
- A designed palette, not an inversion.
Three details worth testing
Turn VoiceOver on with the interface in English and a vehicle note written in Portuguese: it is read in Portuguese.
Set Dynamic Type to the largest accessibility size and walk the dashboard: the numeric displays reflow rather than truncate.
Turn Reduce Motion on while the app is open and in front of you. It takes effect without a relaunch, which is not the default behaviour of the animation library underneath.
Colour is never the message
An overdue inspection is red, and it also says Overdue, and it also carries its own glyph, and the countdown is written out in words. Any one of the four would do on its own. That is the point.
Three test suites hold the line
Accessibility, Dynamic Type and motion policy each have their own automated suite in the codebase, so a later layout change cannot quietly take any of this back. The labels are a promise, and a promise nobody checks is a promise that expires.
Offline-first, and not as a fallback.
The garage lives on the phone. Sync exists so a second device can see it, not so the first one can work. The app is complete in an underground car park, on a plane, or on a phone that has not seen a network in a week.
Encrypted where it sits
Records are written to an AES-256 store on the device, under a key generated on that device, held in the iOS Keychain as THIS_DEVICE_ONLY so it cannot ride an iCloud Keychain restore to a phone the owner no longer has.
Nothing watches
There is no analytics SDK, no advertising SDK, no IDFA and no attribution. Crash and performance diagnostics go out with no user attached and no IP address, and a test in the codebase fails if anybody ever attaches one.
The two declarations are kept honest by a test
Apple asks for the App Privacy questionnaire and for a privacy manifest, and a reviewer can see both. Ours are transcribed into a test that fails if either side drifts from the other, because two published statements that disagree is worse than one.
It can be locked
An optional Face ID lock covers the whole app, including a privacy cover in the app switcher, because a car's history is a home address, a workplace and a routine written down in one list.
It behaves like an iPhone app.
The integrations are the ones that earn their place in a maintenance record, built properly rather than checked off.
- App Intents
- Five, in the app target rather than an extension: Check odometer, Check next service, Check this month's spend, Update odometer and Log fuel. The read intents answer in a snippet without opening the app.
- Siri Shortcuts
- App Shortcuts with spoken phrases, so "log fuel" reaches the right vehicle without a tap.
- Home Screen quick actions
- Long-press the icon to add a record or jump to the active vehicle.
- Reminders
- Local notifications for an inspection, a policy renewal or a service coming due. No push, no server pinging a phone.
- PDF export
- A vehicle's full history as a document, which is what a private sale or a warranty claim actually asks for.
- Sharing
- A vehicle can be shared with the people who drive it, with the owner deciding who may write.
A document you own, not a dashboard you visit.
The interface is typographic. Structure is drawn with hairlines and whitespace instead of cards and borders, which is why the app looks like this page, or rather why this page looks like the app.
Three voices
Archivo Expanded for display, Inter Tight for the interface, Geist Mono for anything measured. A number set in a monospaced face reads as a number, and a column of them lines up.
One accent per screen
The electric blue is spent once and only where it means something. A page where everything is highlighted is a page where nothing is.
Air is the highest-leverage number
Sections separated by forty points read as chapters. The same content at sixteen reads as an undifferentiated list, which is exactly what makes an interface feel generated rather than composed.
One developer, in Portugal.
OdoKeep exists because keeping a car properly is mostly paperwork, the paperwork is different in every country, and the apps that offer to help mostly offer a spreadsheet with rounded corners.
The accessibility work is not a compliance exercise and the ten locales are not a growth tactic. They are both the same decision: a car is owned by whoever owns it, and an app that only serves the sighted, the English-speaking and the recently-updated is an app that decided which of those people counted.
The fuel price feature exists because that data has been public in five European countries for years, paid for by the people who then could not easily read it. Putting it in the app was three weeks of work and no new business model.