Skip to main content

It's time to stand up

StillTime

StillTime is a lightweight Apple Watch companion app I built to track how long I've been sitting and help visualize my standing habits throughout the day. Inspired by the Apple Activity ring, it displays a circular clock where each segment represents an hour. The app encourages regular movement by showing when you last stood—and how long you’ve been sedentary since.

While the Apple Watch includes built-in stand goals, I often found myself passively waiting for the hourly reminder. In reality, I sometimes need a break after 40 minutes—not a full hour, and definitely not just 15. I also wanted to track how long I was continuously sedentary to better understand my habits and nudge myself to move at least once every 30 minutes. StillTime offers a more flexible and visual approach to help me make healthier decisions throughout the day.

Why I Made It

As someone who works long hours at a desk, I wanted a quick visual reference for how sedentary I’ve been. Apple Watch has built-in stand goals, but I wanted something more granular and persistent: an actual clock-style ring that showed when I moved, not just that I stood up once per hour.

How it works

Apple Watch determines stand activity by analyzing wrist motion alongside accelerometer and gyroscope data. If you move continuously for at least one minute while wearing the watch, it records a stand event for the corresponding hour block in HealthKit.

StillTime takes a more granular approach by using step counts from HealthKit to estimate sedentary time minute-by-minute. Once a user surpasses a small step threshold, StillTime logs a movement event for that specific 1-minute interval. By scanning all intervals from the start of the day to the present, the app reconstructs a timeline of active and inactive periods, allowing it to highlight long stretches of sedentary behavior, independent of the Apple Watch’s hourly stand logic.

Each hour on the ring is color-coded:

  • Green: You stood that hour.
  • Blue: You didn’t.
  • Dark gray: No data is available (e.g. if you weren’t wearing the watch).

The app also shows the time elapsed since your last detected stand, which is useful if you’re trying to build healthier habits during desk work or long sessions of focus.

  • Step data is retrieved using HKStatisticsCollectionQuery, grouped by 1-minute intervals.
  • Each minute is checked to see whether it contains at least 10 steps (a configurable threshold) to count as movement.
  • A rolling analysis computes the longest continuous sedentary period between 9am and 5pm.

This gives the user two complementary views:

  • The watch ring shows whether you moved each hour.
  • The iPhone summary shows how much you moved within each hour.
    • A horizontal dot bar visualizes each workday hour, blending color intensity based on the proportion of active minutes.

This level of granularity gives more actionable insights than the standard stand ring alone.

Screenshots

Clock View

Clock View

This screen shows a circular ring where each segment represents one minute and color is based based on detected movement.

Summary View

Summary View

This screen shows a dot for each hour between 9am and 5pm, color-coded by activity level, and a summary of your movement streaks.

Technical Considerations

  • All data is fetched and processed locally on device. The app does not send or store any HealthKit data externally.
  • The app uses a Timer to refresh HealthKit data periodically. Because HealthKit does not provide live updates, we poll every minute to keep "time since last stand" accurate.
  • We use HKStatisticsQuery for single-hour summaries and HKStatisticsCollectionQuery for bulk data grouped by minute.
  • SwiftUI’s @StateObject and @EnvironmentObject manage UI reactivity when HealthKit data updates.

What I Learned About HealthKit

  • HKCategoryTypeIdentifier.appleStandHour marks standing within hour blocks, so you can't get minute by minute stand events from it. A startDate within an hour just means you moved enough at some point during that hour.
  • Stand events are credited for the full hour once triggered. This means a stand at 8:01 AM makes the ring green for 8:00–9:00 AM—even if you remain seated the rest of the time. This discrepancy inspired me to reconcile ring color and actual movement with a more precise “time since last stand” calculation.
  • Privacy comes first: HealthKit data requires explicit permission, and it's only available after the user approves access.
  • HealthKit doesn’t push updates in real time. I set up a timer to re-fetch data periodically to keep the ring up to date.
  • Simulators don’t support HealthKit data, so I had to test everything on an actual device.

Future Ideas

  • Notifications when you’ve been sitting too long (customizable beyond Apple’s default 1-hour reminder)
  • Lock screen widgets or Live Activities for glanceable summaries
  • Passive insights about your daily patterns (e.g., “You typically move less between 2–4 PM”)
  • Support for non-watch users using only phone-based step data
  • Oura Ring integration as a fallback or complement for stand detection
  • Trend charts over time showing percentage of active hours, average sedentary stretches, and consistency streaks

Source code: https://github.com/kimberashman/last-stand