GymTracker: offline atlas and Smart Swap for iOS
How I evolved GymTracker with SwiftUI, CoreData, 1,324 offline exercises, bilingual search, Smart Swap, safe migration and zero data collection.
GymTracker is the first application I designed, developed and published on the App Store as the sole person responsible for the product. It is a native iPhone app built with Swift, SwiftUI and CoreData to log workouts, track progressive overload and understand training progress without relying on spreadsheets, scattered notes or external services.
The short answer about the project is this: GymTracker turns the gym notebook into a fast, private and offline-first iOS experience. Users can create routines, record weight, repetitions and RPE, review their history, visualize metrics such as volume, estimated one-rep max, body weight and training consistency, and in its new evolution it adds an offline atlas of 1,324 exercises with bilingual search, filters, favorites, step-by-step instructions and Smart Swap to replace exercises without breaking the structure of a routine.
Update (August 2026): GymTracker 1.3 is now available with a personalized plan builder, interval running mode and a unified history. Read what's new in 1.3.
Project summary
| Area | Result |
|---|---|
| Problem | Logging and understanding strength progression without friction |
| Platform | Native iPhone application |
| My role | Sole designer and developer |
| Stack | Swift, SwiftUI, CoreData and Xcode |
| Architecture | MVVM with offline-first local persistence |
| Privacy | No data collected |
| Languages | Spanish and English |
| Status | Published for free on the App Store |
| New evolution | Offline atlas, Smart Swap, accessible technique and safe migration |
The public App Store listing identifies Gorka Hernandez Villalon as the developer, shows a 5.0 out of 5 rating from three ratings at the time of publishing this article and confirms that the application does not collect data.
The problem: recording data does not always make it useful
Logging sets during strength training is easy. Making those records useful several weeks later is harder. Progressive overload requires quick answers to practical questions:
- What weight and repetitions did I complete last time?
- Is my total volume increasing, or am I only accumulating sessions?
- How is my estimated one-rep max evolving?
- Am I training consistently?
- How does my body weight change alongside performance?
Many applications address this by adding more features, accounts, subscriptions and screens. My goal with GymTracker was the opposite: reduce the distance between finishing a set and saving a piece of data that can support the next decision.
The interface was designed for the real gym context: a dark theme, large buttons, fast logging and direct access to history. The app does not try to replace a coach or promise automatic results. Its job is to preserve useful information and return it clearly.
Designing the core flow first
Before thinking about charts or profiles, the critical flow was recording a set. If that action felt slow, no later visualization would compensate for the friction.
The product core revolves around three actions:
- Prepare a custom routine with the exercises and order each user needs.
- Log a session quickly by recording weight, repetitions and RPE.
- Review history and progression to decide how to approach the next workout.
This sequence also helped prioritize development. Every new feature had to improve at least one of those actions. The heatmap, for example, is not only a visual element: it makes consistency understandable at a glance. Volume and estimated one-rep-max charts turn isolated records into a trend.
The evolution: offline exercise atlas
The first version of GymTracker solved logging well, but it was still limited in one key area: helping users choose exercises and understand alternatives. That is why the next evolution of the product adds an offline atlas with 1,324 exercises built from a reproducible MIT dataset.
The atlas supports:
- exercise search in Spanish and English;
- filters by muscle area and equipment;
- favorites;
- step-by-step instructions;
- access to technique during a workout;
- useful browsing even without a connection.
Keeping it offline fits the original philosophy of GymTracker. At the gym, I do not want the user to depend on an API, an account or unstable network coverage just to check a chest, back, leg or shoulder alternative.
Smart Swap: replacing exercises without losing context
Another important improvement is Smart Swap. When a user cannot perform an exercise, the app can suggest muscle-compatible substitutions and explain why they fit.
The interesting part is not only showing a list of alternatives. The system preserves:
- sets;
- repetitions;
- rest time;
- routine structure;
- workout history.
That avoids a common problem in gym apps: changing an exercise breaks context. In GymTracker, the substitution tries to respect what the user was already doing and reduce friction during the session.
SwiftUI for a native interface
Choosing SwiftUI allowed me to build the interface with declarative components and keep views connected to application state. For an app with forms, lists, histories, charts and different workout states, that relationship between data and UI is especially important.
The application follows an MVVM architecture. Separating views, presentation state and models prevents screens from accumulating all the logic. This matters when the same information appears in several places: one session affects history, charts and the heatmap, but every view should not need to reinterpret it independently.
SwiftUI also supports another project goal: GymTracker should feel like an iOS app rather than a website placed inside a phone. Navigation, controls and visual hierarchy follow patterns familiar to iPhone users.
CoreData and an offline-first architecture
GymTracker uses CoreData to store routines, exercises, sessions and metrics locally. This choice responds to two product requirements:
- the app must work at the gym even without network coverage;
- workout data does not need to leave the device to provide value.
In an offline-first architecture, local persistence is not a fallback. It is the main source of truth. Users can record and review information without waiting for an API or creating an account. That reduces dependencies, removes network latency and simplifies the experience.
The trade-off is that the data model matters greatly. Routines, exercises and records need consistent relationships so history and charts remain reliable. A saved set is not only one row: it feeds later calculations and becomes part of the user's training history.
Expanding the catalog also required a safe migration. The app must be able to update existing installations without losing routines, logs or history. That is why the catalog import was designed with unique identifiers, deduplication and a reproducible checksum.
Turning records into useful information
Saving data was only half of the problem. The other half was presenting it in a way that helps people interpret progress.
GymTracker includes:
- complete workout history;
- automatic total-volume charts;
- estimated one-rep-max progression;
- a profile with body-weight charts;
- a heatmap of completed sessions.
Each visualization answers a different time scale. History helps compare the current session with the previous one. Charts reveal trends. The heatmap summarizes consistency. Together, they move the experience from "I trained today" to "this is how my training is evolving."
Privacy as an architecture decision
Privacy was not added at the end as legal copy. It directly shaped the architecture: GymTracker stores information on the device and does not collect user data. This practice is publicly declared in its App Store listing.
Not requiring an account or sending workouts to a server has several benefits:
- fewer steps before using the app;
- full offline operation;
- less data exposure;
- no unnecessary remote infrastructure.
It also means accepting a limitation: a purely local architecture does not provide cross-device synchronization by default. For this project, I chose to prioritize simplicity, speed and privacy instead of building a cloud layer without a clear need.
Licenses, dataset and App Store
For the atlas, I used data and instructions from an MIT dataset pinned to a concrete commit so the
catalog can be reproduced. I did not copy third-party images or GIFs into the app; media is treated
separately and attribution is documented in THIRD_PARTY_NOTICES.md.
Preparing the update also includes pieces required for App Store distribution:
PrivacyInfo.xcprivacymanifest;- visible privacy policy link inside settings;
- opaque icons without alpha channel;
- localized Spanish and English copy;
- clear declaration that the app collects no data.
This is not decorative work. Publishing an iOS app requires product, privacy, licenses and distribution to stay aligned.
Taking an independent app to the App Store
Publishing GymTracker changed the project. It stopped being an interface that worked in my environment and became a product other people could install, rate and use with their own data.
That step forces attention toward areas a prototype can hide:
- real compatibility across devices and iOS versions;
- copy and experience in Spanish and English;
- error handling outside the ideal path;
- a clear product description;
- privacy declarations;
- maintenance after the first release.
The published version introduced compatibility improvements, a profile with body-weight charts, a workout heatmap, fixes and Spanish and English support. That cycle taught me that launching is not finishing. It is the start of receiving real signals about what works.
What I built
I handled GymTracker end to end as its sole designer and developer:
- problem definition and scope;
- design of the main user flows;
- SwiftUI interface implementation;
- CoreData modeling and persistence;
- MVVM architecture;
- creation of the offline atlas and bilingual search;
- Smart Swap implementation and substitution logic;
- deduplicated import and safe migration;
- progress visualization;
- Spanish and English localization;
- App Store preparation and publication.
For me, this breadth is one of the project's most valuable aspects. It is not only about knowing Swift. It is about making connected decisions across product, experience, data, privacy and distribution.
What I learned
GymTracker left me with four main lessons:
- The speed of the primary action defines the product. At the gym, logging a set needs to feel almost immediate.
- Data needs context. History is useful; a visual trend helps people make decisions.
- Privacy can simplify a system. Collecting no data removes infrastructure and friction when the product does not need an account.
- A large catalog needs product rules. Importing exercises is not enough: they need to be searchable, filterable, deduplicated, translated and useful during a real workout.
- Publishing raises the standard. Compatibility, languages, errors and maintenance become part of the technical work.
Result
The result is a public, free and verifiable iOS application that solves a specific problem with a focused architecture and a clear evolution toward a more complete training app. GymTracker is available on the App Store, and its extended case study is available in the projects section of my portfolio.
GymTracker represents the kind of product I want to build: useful, focused software that can explain clearly why it exists. To discuss iOS development, SwiftUI or a mobile project, reach out through my contact page.