A free, open-source time and task management CRM built around four planning horizons — Today, This Week, This Month, This Year — with live timers, reminders, weekly scheduling, analytics, and shareable public streak profiles.
🔗 Live app: track-time-web.vercel.app
Most task trackers either forget the time dimension or bolt it on. Track Time treats time as the primary unit: every task belongs to a horizon, carries a planned duration, and gets measured against the time you actually spent — so "productive" is something you can see, not guess.
It's free to use today, actively maintained, and open source so anyone can self-host it, extend it, or contribute back.
- Four time horizons — Day, Week, Month, Year — one task model, filtered by planning window
- Live timer — start/stop tracking on any task, with manual time-entry as a fallback
- Weekly work slots & calendar — assign tasks to recurring time slots and see them on a real calendar
- Reminders that fire — browser push notifications, live countdowns, and an audio alarm when a slot starts
- Reports & analytics — planned-vs-actual trends, best weekdays, most productive days, full schedule history
- CSV export — download logged time as a CSV for client invoicing
- Public streak profiles — opt-in
/u/<username>page showing your streak, hours logged, and a GitHub-style activity heatmap — never your actual tasks - Multiple sign-in methods — email OTP, password, or Google (Firebase)
- Role-based admin — a superadmin analytics view across all users
- Installable PWA — add to home screen on Android, desktop Chrome, or Edge
- Companion mobile app — Expo/React Native app for viewing today's tasks on the go
| Landing page | Login |
|---|---|
![]() |
![]() |
| Dashboard overview | All Tasks |
|---|---|
![]() |
![]() |
| Time Tracker | Daily Schedule |
|---|---|
![]() |
![]() |
| Categories | Summary & Reports |
|---|---|
![]() |
![]() |
| Profile & streak | Public streak profile |
|---|---|
![]() |
![]() |
- Web and backend: Next.js App Router
- API layer: Next.js Route Handlers under
web/src/app/api - Database: MongoDB with Mongoose
- Cache: in-memory process cache for short-lived task reads
- Authentication: Email OTP, password, and Google (Firebase) with httpOnly session cookies
- Email delivery: SMTP through Nodemailer
- Mobile: React Native with Expo
- Styling: Tailwind CSS
- Repository style: npm workspaces monorepo
Track_Time/
├─ web/
│ ├─ lib/
│ │ ├─ dbConnect.js MongoDB serverless connection utility
│ │ ├─ auth.js Sessions, OTP hashing, password hashing
│ │ ├─ streak.js Streak/activity computation for public profiles
│ │ └─ cache.js Free in-memory cache utility
│ ├─ models/
│ │ ├─ Task.js Task schema (horizon, priority, slots, alarms)
│ │ ├─ User.js Auth user, role, and public-profile fields
│ │ ├─ TimeLog.js Logged time entries
│ │ ├─ Category.js Task categories
│ │ ├─ DailySchedule.js Planned vs actual hours per day
│ │ ├─ OtpToken.js Email OTP schema
│ │ └─ Session.js Login session schema
│ ├─ src/
│ │ ├─ app/
│ │ │ ├─ api/ Route handlers (tasks, time-logs, auth, profile, ...)
│ │ │ ├─ dashboard/ Main web dashboard (tasks, timer, reports, profile)
│ │ │ └─ u/[username]/ Public streak profile page
│ │ └─ components/ Shared UI components
│ ├─ package.json
│ └─ vercel.json
├─ mobile/
│ ├─ screens/
│ │ └─ HomeScreen.js Today's tasks, read-only mobile view
│ ├─ services/
│ │ └─ api.js Mobile API client
│ ├─ App.tsx
│ └─ package.json
├─ package.json Root workspace scripts
├─ package-lock.json Root npm lockfile
├─ LICENSE MIT license
├─ .gitignore Ignore rules for both apps
└─ README.md
This project uses npm workspaces. When you run npm install from the root, npm installs and hoists workspace dependencies into the root node_modules folder. That root node_modules belongs to the full monorepo and supports both web and mobile.
You may also see mobile/node_modules because Expo created/install-managed mobile dependencies during scaffolding. Both node_modules folders are local development artifacts.
They are ignored by Git and should not be pushed to GitHub.
From the root folder:
npm installThis installs dependencies for the root workspace, web, and mobile.
Environment files are ignored by Git. Create them locally and add the production values in Vercel.
Create:
web/.env.local
Use:
MONGODB_URI=your_mongodb_connection_string
MONGODB_DB=track_time
SMTP_HOST=smtp.gmail.com
SMTP_PORT=465
SMTP_SECURE=true
SMTP_USER=your_gmail_address
SMTP_APP_PASSWORD=your_gmail_app_password
EMAIL_FROM="Track Time <your_gmail_address>"
AUTH_SECRET=use_a_long_random_secret_at_least_32_characters
SUPERADMIN_EMAIL=your_superadmin_email
ADMIN_FEEDBACK_EMAIL=your_feedback_inbox_email
NEXT_PUBLIC_FIREBASE_API_KEY=your_firebase_web_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.firebasestorage.app
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
NEXT_PUBLIC_FIREBASE_APP_ID=your_firebase_app_id
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=your_measurement_id
FIREBASE_WEB_API_KEY=your_firebase_web_api_key
MONGODB_DBis case-sensitive on MongoDB Atlas — keep it consistent across every environment (local, Vercel) or connections will fail with a "db already exists with different case" error.
After the web app is deployed on Vercel, create:
mobile/.env
Use:
EXPO_PUBLIC_API_BASE_URL=https://your-vercel-domain.vercel.appFor local Android emulator testing:
EXPO_PUBLIC_API_BASE_URL=http://10.0.2.2:3000For a physical phone on the same Wi-Fi:
EXPO_PUBLIC_API_BASE_URL=http://YOUR_COMPUTER_LAN_IP:3000From the root:
npm run dev:webOpen:
http://localhost:3000/dashboard
If you are not logged in, the app redirects to:
http://localhost:3000/login
The API runs on the same local server:
http://localhost:3000/api/tasks
http://localhost:3000/api/tasks?timeHorizon=1_Day
From the root:
npm run start:mobileThen use the Expo terminal options to open Android, iOS, or Expo Go.
Android emulator:
npm run android:mobileiOS simulator on macOS:
npm run ios:mobileExpo web preview:
npm run web:mobileFrom the root:
npm run lint:web
npm run build:web
npm run typecheck:mobileRequest OTP:
POST /api/auth/request-otpBody:
{
"email": "user@example.com"
}Verify OTP:
POST /api/auth/verify-otpBody:
{
"email": "user@example.com",
"otp": "123456"
}If the email is new, the user is created automatically. If the email already exists, the user is logged in. The configured SUPERADMIN_EMAIL receives the superadmin role.
Password and Google sign-in are also available at /api/auth/password-login and /api/auth/firebase-google.
GET /api/tasksOptional filter:
GET /api/tasks?timeHorizon=1_DayValid timeHorizon values:
1_Day
1_Week
1_Month
1_Year
POST /api/tasksExample body:
{
"title": "Prepare daily operations report",
"description": "Compile execution updates and outstanding blockers.",
"status": "pending",
"timeHorizon": "1_Day",
"timeAllocated": 120,
"timeSpent": 30,
"isAlarmSet": true,
"alarmTime": "2026-08-08T09:00:00.000Z",
"pushToken": "expo_push_token_here"
}timeAllocated and timeSpent are stored in minutes.
GET /api/time-logs/export
GET /api/time-logs/export?start=2026-08-01&end=2026-08-31Returns a CSV download of the authenticated user's logged time, ready for client invoicing.
PATCH /api/profileBody (any subset):
{
"username": "yourname",
"publicProfile": true
}Once set, the profile is visible at /u/<username> — showing current streak, longest streak, hours logged, and a 12-week activity heatmap. Off by default; task and time-log content is never exposed.
- Push this repository to GitHub.
- In Vercel, import the GitHub repository.
- Set the Vercel Root Directory to:
web
- Keep Framework Preset as Next.js.
- Use:
Install Command: npm install
Build Command: npm run build
Output Directory: .next
- Add the same environment variables listed under Web Environment in Vercel's project settings.
- Deploy.
- Open:
https://your-vercel-domain.vercel.app/dashboard
Login page:
https://your-vercel-domain.vercel.app/login
Superadmin analytics:
https://your-vercel-domain.vercel.app/superadmin
The backend API will be available on the same Vercel domain:
https://your-vercel-domain.vercel.app/api/tasks
After Vercel deployment, copy your Vercel domain into:
mobile/.env
Example:
EXPO_PUBLIC_API_BASE_URL=https://track-time-web.vercel.appRestart Expo after changing this value:
npm run start:mobileTrack Time is open source and contributions are welcome — bug fixes, new features, mobile parity work, or docs improvements.
- Fork the repository and create a branch off
main. - Make your change, keeping it scoped to one concern per PR.
- Run
npm run lint:webandnpm run build:webbefore pushing. - Open a pull request describing what changed and why.
If you're planning a larger feature, open an issue first so it can be discussed before you invest the time.
Track Time is MIT licensed — free to use, modify, and self-host, including commercially.









