SNKRTRKR is a universal iOS and macOS app for monitoring Nike sneaker prices across Australian retailers. It watches for price drops, surfaces historical lows, and keeps track of what you own.
I kept missing sales. I'd check Nike, then Foot Locker, then JD Sports, then forget what I'd seen on the first one. There was no single place that told you whether the price you were looking at was actually good. I built SNKRTRKR to solve that for myself, and it grew from there.
Nike and its retail partners don't make it easy to compare prices across storefronts. A shoe listed at full price on one site might be 40% off on another, and there's no way to know without checking each one individually. Knowing whether a price is genuinely good requires history, something none of the retailers expose.
SNKRTRKR aggregates that data and presents it in one place, with enough context to actually make a decision.
The app is built in SwiftUI using Swift 5.9's @Observable macro, which simplified state management considerably over the older ObservableObject pattern. A single view model manages fetch lifecycle, loading states, and stale-fetch cancellation through a generation counter—each new request increments it, and any response from a prior generation is discarded.
User data–watched styles, size preferences, the personal collection–syncs across devices through a custom @CloudStorage property wrapper I wrote that writes simultaneously to UserDefaults and NSUbiquitousKeyValueStore. Collection photos go to iCloud Documents, compressed and resized before saving.
The same codebase runs on macOS. Adapting it meant swapping a few platform-specific APIs—UIImage for NSImage, .glassEffect() for .regularMaterial, a menu bar shortcut for manual refresh—but the architecture didn't need to change. SwiftUI largely delivered on its promise there.
The API I built to drive it runs from a Docker container and gently scrapes Nike, Foot Locker, JD Sports, and Culture Kings on a schedule and aggregates results by style code, grouping the same shoe across multiple sources. The API exposes a full catalogue endpoint and a slim watch endpoint for background fetches on only the styles a user cares about.
Scraping takes time, so the server returns a warming flag when fresh data isn't ready. The app handles this gracefully–showing stale data immediately and polling silently until a fresh response arrives.
iOS background app refresh runs on a 15–60 minute interval. When it fires, the app loads a snapshot of the last-known prices, fetches only the user's watched styles, diffs the result, and fires local notifications for drops or newly discounted items.
Early on I noticed retailers occasionally oscillate between in-stock and sold-out states within the same day. Without a safeguard, a single pair of shoes could generate a dozen alerts overnight. I added a 24-hour cooldown on sale notifications to prevent that.
The collection tab is a personal inventory for the shoes you own. You can log a style manually, attach a photo, and record which sizes you have. But the more interesting path is through the scanner.
DataScannerViewController from VisionKit handles live text recognition against the camera feed. Rather than scanning barcodes, it reads printed text and runs it against a regex that matches Nike style codes in both formats: alphanumeric like AV3595-002 and numeric like 604133-139. Point your camera at a receipt or a tag, it finds the code, matches it against the catalogue, and adds the style to your collection. No typing.
The didFind flag ensures it fires exactly once per scan session. A guard at the call site checks scannerSupported before the scanner UI is ever shown, keeping it iOS-only without polluting the shared codebase. The whole thing is about 50 lines.
Photos are stored in iCloud Documents alongside the rest of your data, resized and compressed before saving.
SNKRTRKR is free to download. Watching up to three styles and browsing the full catalogue are available to everyone. Push notifications and adding more than three styles to your collection require a one-time purchase.
I built the app for myself and open-sourced the problem-solving. The purchase is for people who want to use it seriously, and the passive income offsets the cost of keeping the backend running.
As this is a real product, live on the App Store, which I'm promoting to friends through Instagram, I had to fulfill some requirements. My first instinct was to borrow Nike's own branding; however, I hear there are rules and stuff. So, I went abstract, and through some light iteration, I've arrived at a result where I've reduced the Tuned Air logo to its simplest form and borrowed my portfolio site's own font for marketing materials.