← Case Studies
Tally app icon

Tally - Time Tracker

A time tracker for freelancers and small teams. Native iPhone, iPad, Apple Watch, Mac and Vision Pro apps, a web app, and an Android beta, all on one backend, connected to Jira, Linear, Asana, ClickUp, Trello, monday.com, Basecamp, GitHub, GitLab, Slack, and Google Calendar. Designed, built, and shipped solo.

Tally on a MacBook: the timer running for Acme Corp on Jira ticket ACME-12
Tally on iPhone: the timer running for Blue Sky Studio
The native Mac and iPhone apps
Swift · SwiftUI · React · Vite · Supabase · StoreKit · Stripe · Capacitor · 2026
Role
Sole developer
Platforms
iPhone · iPad · Watch · Mac · Vision Pro · Web · Android
Integrations
Jira · Linear · Asana · ClickUp · Trello · monday.com · Basecamp · Notion · Todoist · GitHub · GitLab · Figma · Slack · Calendar · Stripe · Claude
Status
Live on iPhone, iPad, Watch, Mac & Vision Pro · Android closed beta (as of Oct 2026)
Traction
~300 downloads · 63K+ App Store impressions

The Problem

Freelancers and small teams lose billable hours when tracking lives in a spreadsheet or someone's memory, and the hours that do get logged rarely make it back to the ticket the client is looking at.

Every tool we tried was either built for solo freelancers with no team layer, or enterprise software that cost more than the project was worth. Tally works for one person or a whole team, runs on the devices people already use, and meets them in the tools they already work in: a timer starts from the ticket you're on, and the time lands back where your team will see it.

The other half of the problem is trust. A client paying by the hour sees a number and has to take it on faith. Tally gives every hour a receipt: the pull requests, commits, meetings and design saves behind it, on a report link the client can open without an account.

See It Work

Short clips from the native iPhone app and the web app. Pick one, or let them play in turn.

How It Works

On the Web

The marketing site and web dashboard are React + Vite on Vercel, with a live demo account that reseeds itself nightly.

tallytimetracker.com

Open full screen ↗

On Your Phone

Native SwiftUI on iPhone, and the same account on Android through a Capacitor build of the web app.

9:41

Landing page - mobile layout

iOS App

The running timer for Blue Sky Studio with Pause and Stop

Timer

The client picker: Acme Corp under the Design Team, and personal clients Blue Sky Studio and River North Group

Client picker

After stopping: a title and note for the session, type of work and billable

Title and note

Reports for this week: 18 hours 39 minutes against a 20 hour goal, split by client and by type of work

Reports

The Activity calendar with Wednesday, October 21 selected: 5 hours 30 minutes across River North Group and Blue Sky Studio

Activity

Android Beta

The Android dashboard: 18 hours 40 minutes this week, a 4 day streak, estimated earnings and the Acme Corp contract

Dashboard

Reports on Android: hours and earnings this week, by client

Reports

iOS Integration

Tally Live Activity on the iOS lock screen showing the running timer

Lock screen Live Activity

A Live Activity keeps the running timer on the Lock Screen and Dynamic Island, widgets show today's hours, Siri can start and stop timers, and a Focus filter switches Tally to your work client automatically.

Tally home screen widgets - large, medium, and small

Apple Watch

Start, pause, and stop a timer from your wrist — no phone needed. When you stop, the session syncs to your iPhone and every other device.

Tally on Apple Watch: Acme Corp with a green play button to start the timer

Tap to start

Tally on Apple Watch: timer running

Timer running

Tally on Apple Watch: timer paused with resume and stop buttons

Pause & resume

iPad

On iPad the sidebar stays open, so Timer, Reports, Activity and Team are one tap away without covering the page.

Tally on iPad: Reports with this week's hours by client and by type of work
Tally on iPad: Acme Corp with 88 hours, total earnings, the Hours Report PDF and every session

Native macOS App

A fully native macOS target — not Catalyst — with Mac patterns throughout: sidebar navigation, right-click to edit or delete sessions, and Mac-specific sign-in (Apple and email; Google has no Mac SDK).

Mac and iOS share the same SwiftUI source, with iOS-only APIs excluded by #if os(iOS) guards. A shared bundle ID enables Universal Purchase: buy on iPhone, unlocked on Mac.

Tally on macOS: the Design Team for Acme Corp at 25 hours 30 minutes of an 80 hour weekly goal, with each member's role and hours and one invite pending

Team workspaces in the Mac app: a shared weekly goal, roles and invites

Architecture

Native SwiftUI Apple apps iPhone · iPad · Apple Watch · Mac · Vision Pro Widgets · Live Activities · Siri
React · Vite Web app Hosted on Vercel
Capacitor (beta) Android Wraps the web app
Supabase
Postgres + row-level security Edge Functions Scheduled jobs
Integrations
  • Stripe
  • Jira
  • Linear
  • Asana
  • ClickUp
  • Trello
  • monday.com
  • Basecamp
  • Notion
  • Todoist
  • Figma
  • GitHub
  • GitLab
  • Slack
  • Calendar
  • Claude
Every app reads and writes the same Supabase project. Integrations connect through Edge Functions, so tokens and secrets stay on the server.

Payments. Tally is free for up to five clients, with one paid plan, Tally Premium, at $4.99 a month or $39.99 a year. StoreKit, Google Play Billing and Stripe all feed one Supabase subscriptions table, with no third-party billing service. Only the server writes to it (Stripe through a webhook, App Store purchases verified against Apple's signature), so a client can't grant itself Premium. App Review took nearly 10 rejections, each for a different guideline, before the first release.

Push notifications. An Edge Function delivers through APNs and Firebase Cloud Messaging, signing a JWT per request and pruning dead tokens. Permission is asked after the first tracked session, not at launch.

Automated email. A weekly summary of each user's hours and a note for users who've gone quiet, sent by scheduled jobs through Resend with signed one-click unsubscribe links.

Integrations. Integration tokens are encrypted before they're stored, and saved sessions post back to the tool they came from: a Jira worklog, a Linear comment, an Asana or ClickUp time entry, a Trello comment, a monday.com update or a Basecamp timesheet entry. Inside Tally, a Jira ticket shows its details and comments, and you can reply or change its status without leaving the timer. GitHub is read-only and limited to the repositories you pick. The Claude connector is an MCP server over the same data the apps use.

Engineering Highlights

What Was Hard

Logging time to Jira exactly once. When you save a session on a Jira or Linear ticket, Tally posts the time back to that ticket. But a save can arrive twice: a double click, or a save that stalls on a bad connection, is kept to retry, and then lands after all. A duplicate worklog shows the client hours that never happened.

So I made both steps safe to repeat. The app gives each session its id before the first try, so the database refuses a second copy and the app counts that as saved. Before posting to the ticket, the server function claims the session: a second request while the first is posting gets "already logged", a failed post gives up its claim so it can be tried again, and a claim stuck for two minutes is taken over. The worklog's id is stored on the session once it's posted.

Server tests cover the claim, and end-to-end browser tests check that each save on a Jira or Linear ticket logs time exactly once.

One timer on every device, even offline. Start the timer on the website and it should be running on your iPhone, Mac and Watch, and pausing or stopping it anywhere should stop it everywhere. Two things made that hard: device clocks disagree, and a phone can lose signal right as you stop.

The running timer is one row per user, pushed to every device over Realtime. The database stamps each change with its own time, so no device's clock decides which change is newer, and each timer gets a fresh id so a device can tell "this timer changed" from "a new timer started". A stop made offline is sent before the device reads the shared timer again, and a session saved offline keeps its id, so it lands once when the connection returns.

User Research

After launch, I manually reviewed the email addresses of users who had created accounts and reached out to 30 of them directly. Most didn't respond, but one did: a freelance product designer who was using Tally to track her hours and earnings. She is the clearest signal I have of who Tally is really for.

Her feedback drove concrete product decisions:

  • Billing cycles per client — her clients bill on different schedules, some monthly and some weekly, so one fixed monthly cycle didn't fit. I added monthly (by day of month) and weekly (by weekday) billing cycles for each client, plus a "Last Billing Period" button on invoices that auto-fills the correct date range.
  • Choose when the week starts — she asked to pick the first day of the week, since not everyone works Monday to Sunday. It's now a setting, and a team owner can set one for the whole team.
  • Client settings that are easy to reach — editing a client meant going through Activity first. I moved Client Settings into the Account tab, with TipKit tips on first use.
  • The tools she already uses — she works in Figma and Todoist. Todoist tasks can now start a timer the same way Jira, Linear and Notion tickets do, and edits to Figma files show up as untracked time you can add.
Tally Clients screen showing per-client billing cycles: Acme bills from the 15th, River North from the 1st, Blue Sky every Monday, with a tip explaining rates and billing cycles
Per-client billing cycles, built from her feedback

One respondent who explains their workflow is worth more than a hundred survey answers.

Finding Where People Drop Off

Downloads were growing, so I queried who actually used Tally after signing up. Of 125 accounts, only about a third had ever tracked a single session. The biggest drop wasn't between free and paid; it was between creating an account and starting the first timer.

The setup pushed people through the wrong things first: rates, a plan picker, integrations. So I changed the order of the first minutes:

The number to watch is the share of new sign-ups who track at least once, against that one-third baseline. Sign-up source is now tagged too, so I can see which channel brings people who stay.

Now on Vision Pro

Tally for Apple Vision Pro

A native visionOS app, now on the App Store: the same SwiftUI source as iPhone and Mac, in a glass window with a sidebar, plus a timer volume you can place anywhere in the room and an ornament to open it. Text and progress are sized to read from across the room.

Learn more ↗
Tally on Apple Vision Pro: a glass window in a living room with the sidebar, an empty timer ring, Acme Corp and River North Group goal progress, Start Timer, and an Open Timer Volume button below the window

The Outcome

I use Tally every day on a real freelance contract: the person I work with and I both track our hours for the client in it. That daily use is where most fixes and features come from.

About 300 downloads and 63K+ App Store impressions since launch, built and shipped solo, with one account across every platform. Each release goes out on every Apple platform, the web and Android together; 1.11.0 is the latest.

It's the most complex thing I've built. Not because any single piece is hard, but because seven platforms, several payment paths, a shared backend and a growing list of integrations all have to be right at once.

What I Learned, and What's Next

Shipping the same feature to every platform taught me to put the rules in one place first. When the server owns the truth (the shared timer, the subscription record, the "logged once" claim), every app can be simple, and a new platform like Vision Pro is mostly layout work.

Try Tally

Free to start, no credit card needed. One account works on iPhone, iPad, Apple Watch, Mac, Vision Pro, the web and Android.