App Saturday: BetterKey - building reliable car controls on top of unreliable OEM APIs

What I built

BetterKey is a small iOS/watchOS system that sits on top of OEM vehicle APIs and tries to make remote lock/unlock predictable. The user-facing surfaces are the iPhone app, Apple Watch, Siri Shortcuts, and a few Lock Screen flows. Vehicle commands go through a protocol-based abstraction, with Smartcar as the primary provider.

It is not trying to replace a physical key. It is a lower-friction path for common cases: walking up to the car, or using the watch when the phone is not convenient.

Why I built it

I kept running into small unlock friction: phone in pocket, hands full, OEM app slow to launch, Bluetooth key behavior inconsistent, or the car's own app needing several taps before issuing a command. The real problem was that the system never felt deterministic.

For a lock/unlock app, trust is the product. If the UI says "locked" based on optimism instead of confirmed state, it only has to be wrong once before the user stops believing it.

Architecture / Stack

The iOS and watchOS apps are SwiftUI on Swift 6, using async/await, actors, and u/MainActor on the UI layer. Most client code is shared through Swift packages with platform adapters for iOS, watchOS, and UI tests.

The backend is a Go API on Fly.io. It handles auth, Smartcar/OEM token management, command orchestration, token refresh jobs, and push fanout. Firestore stores state and command metadata; FCM handles delivery.

Deep problem: OEM APIs are not real-time systems

Lock/unlock APIs look simple, but they behave like eventually consistent remote calls into a car that may be asleep, offline, busy, or behind a flaky backend.

A command can be accepted before the car has moved a latch. Status can be stale, providers return 502s, and immediate polling can make success look like failure. Rate limits mean "just poll harder" is not a real solution.

I initially treated command success too much like state success. That broke down quickly, especially around Lock on Depart, where an optimistic "locked" state is worse than no automation at all. Smartcar surfaces this directly: a successful response can carry `X-Command-Confirmation: unconfirmed`, meaning the request was accepted but not confirmed by the vehicle. BetterKey maps commands into `VehicleCommandResult.confirmed` or `.unconfirmed`, and the UI separates "sent but unconfirmed" from "locked."

Deep problem: Park, depart, and Lock on Depart

The naive version is simple: detect departure and issue a lock command. The real version has to account for location accuracy, background limits, duplicate events, stale state, and cases where the user intentionally leaves the car unlocked.

Lock on Depart sits on top of Park Location, which confirms that the car is parked. The coordinator is a phase-driven actor that watches geofence and motion signals, applies cooldown windows, and exits if vehicle state is too stale.

The tradeoff was responsiveness versus unnecessary commands. I biased toward fewer commands and clearer state transitions.

Lock Screen surfaces

The Lock Screen piece is Live Activities and App Intents, not a general purpose lock/unlock widget. That constraint shaped the design: Lock on Depart can expose monitoring/locking state, while Prompt to Unlock can present one narrow action when motion looks like returning to the vehicle. App Intents keep that action on the same command pipeline as the in-app button.

App Review and demo mode

Demo mode mattered more than I expected. App Review, testers, and every developer cannot be expected to have a compatible real vehicle connected through Smartcar.

At the network edge, an `InterceptorNetworkClient` swaps in a noop implementation. At the service layer, a `SimulatorVehicleService` actor provides seeded vehicles, deterministic transitions, and toggleable states like "needs reauth" or "window open."

The tradeoff is that demo mode has to stay honest enough for review and testing. If it drifts too far from production behavior, it stops being useful.

What I learned

- HTTP success can still be UX failure if the state is not confirmed.
- Background constraints shape product design more than UI decisions.
- Lock state UX needs careful language. Pending, confirmed, and unconfirmed are different things.
- Hardware-adjacent apps need a credible demo/review path from day one.
- Automations on physical hardware need a foundation feature you trust.

Happy to answer questions about the architecture.

reddit.com
u/RussellQwerty — 9 days ago

I built BetterKey - a car companion app for locking, unlocking, and small automations (iOS + Apple Watch)

Hey everyone,

I built an app called BetterKey for compatible connected vehicles (via Smartcar). It lets you lock, unlock, and run a few lightweight automations from your iPhone and Apple Watch.

I originally built it because I kept having that annoying “did I remember to lock the car?” moment after walking inside, going to bed, or parking somewhere unfamiliar.

A few things it does right now:

  • Lock and unlock from iPhone or Apple Watch
  • Park Location: saves where you parked so you can find your car later
  • Lock on Depart: can automatically lock the car when you walk away
  • Prompt to Unlock: one-tap unlock on your lock screen and watch when you approach the car
  • Open Window Alert: notifies you if you parked with a window left open and its going to rain/snow.
  • Shortcuts support: build your own automations and flows if you want

The goal is not to replace the key, just to remove some of the small, repetitive “car admin” moments.

It’s live on the App Store and I’m actively iterating based on feedback.

I’d really appreciate thoughts on:

  • Would features like Lock on Depart or Prompt to Unlock actually be useful in your day-to-day?
  • What would make you trust an app like this with your vehicle?
  • Any car-related friction points you wish your current app handled better?

Website: https://betterkey.xyz
App Store: https://apps.apple.com/us/app/betterkey/id6745559471

Thanks for checking it out. Happy to answer questions or go deeper on how it works under the hood.

reddit.com
u/RussellQwerty — 10 days ago

I ran into this a few times with my Apple Watch:

At the beach with sandy hands, or going for a run and leaving my phone behind, I still needed a way to lock or unlock my car.

Most car apps are built for the phone, and the watch versions (if they exist) are slow or barely usable.

I ended up building a watch-first app called BetterKey so I can just do it from my wrist in those situations.

Curious if anyone else actually uses their Apple Watch this way, where you can leave your phone behind and still have everything you need.

App Store: https://apps.apple.com/us/app/betterkey/id6745559471

Happy to answer questions or go deeper on how it works if helpful.

u/RussellQwerty — 2 months ago