Whether loyalty programs are good or bad, and how much we “pay” for our privacy — that’s a topic for a separate discussion. Today I’d like to focus on something more down to earth: user convenience. And, while we’re at it, AI — because these days it’s hard to write anything without bringing it up. 😉 And no, this is not a post about the app from the picture. 😉

Dozens of apps from dozens of providers — each one there just to show a barcode at the checkout. That’s what you actually need. On top of that, of course, the “special offers” — that is, ads the provider wants you to see. Finding the right card in line takes too much time, especially when the store is underground or in a steel-roofed warehouse and that “special offer” decides to load extra lazily. The look on the faces of people behind you says it all. 🙂

This used to be solved beautifully by Stocard — a simple app that gathered all your cards in one place. It had a promotions section, sure, but you could easily skip it: the wallet with your cards was always front and center, worked without internet, and opened in two taps. It worked great for years. Some time ago Klarna acquired Stocard and the slide began: slow loading, ads pushed to the foreground. An app that was supposed to be the remedy for too many promotions became the biggest source of them.

For me that was one step too far, and I deleted it from my phone. Since I have a Claude subscription, I decided to “write” (read: describe what I want and how it should look — spec-driven development in its simplest form) my own app. It took me one evening. In fact, I even published it on the App Store: Scandio

Simple and functional: you scan a card, it lands in your wallet, which you can export to a file and share with others. Everything stays on your device — no ads, no tracking of shopping habits.

Under the hood it’s SwiftUI + SwiftData on iOS 17, with a single LoyaltyCard model and a WindowGroup rooted at the card list. It handles seven barcode formats — EAN-13, EAN-8, ITF, QR, Code 128, PDF417 and Aztec — honestly all the ones I found across my own loyalty cards, but there’s no reason not to extend the list if needed. Rendered barcodes live in a 20 MB NSCache that evicts on memory warnings, and the carousel and detail views pre-cache off the main thread via Task.detached, so by the time a view appears the lookup is O(1). When you pull a card up at the checkout, the app saves your current screen brightness, cranks it to the max so the scanner can read the code through any glare, disables the idle timer, and restores everything when you leave the screen — even if you background the app mid-scan. It’s an option in settings, so if scanners read your codes fine without it, or you just want to save battery, you can disable it. The backup format is versioned JSON with base64-encoded logos, and import validates field bounds and skips duplicates by name + card number. Logo blobs use SwiftData’s @Attribute(.externalStorage) so the SQLite store stays small. By default there are no brand logos shipped with the app — to keep clear of trademark issues. Instead, the app tries to match each card to a fitting emoji — and on newer Apple devices it uses Apple Intelligence to do it. 😉 Overkill? Maybe. But why not, if it’s possible? 😉 And the part I’m proud of: no account, no network calls, no analytics — and because the SwiftData model is already CloudKit-compatible, iCloud sync is a matter of flipping an entitlement the day I’ll need it.

What’s cool about it? I had never written a single line in Swift before, nor anything for an Apple device. I have a solid background in C/C++/CUDA, but no experience with macOS or iOS at all. I used a spec-driven development approach — I defined what the interface should look like and what it should do, and Claude took care of the rest… almost. Later I just made several quick passes with simple tweaks like: “Change this to… and mirror that in the spec folder.” It works. Just like that. Claude also did the thing I definitely wouldn’t have wanted to do myself: full documentation in the form of a website.

Would this app exist without Claude? Probably not — I would have given up before getting through the first Swift tutorial, because there are always dozens of more urgent things on my plate. But this way I have what I need: standing in line at the checkout, my discounts are scanned in a second.

If anyone would like to “port” the app to Android, the code is on GitHub.