A lightweight, privacy-first Windows desktop time tracker with a modern Windows 11-style UI.
FocusLog automatically monitors your active window to track productivity, calculate earnings based on hourly rates, and generate detailed session reports. It features crash recovery, auto-exclusion of system apps, and flexible export options (CSV, JSON, TXT).
- π Automatic Time Tracking: Detects the foreground application and logs usage duration with second-level precision.
- π° Earnings Calculator: Set an hourly rate to see real-time earnings accumulation during work sessions.
- π‘οΈ Smart Exclusion System:
- Auto-Exclude: Automatically ignores system processes (Explorer, Taskbar, Search, etc.) so they don't clutter your data.
- Manual Exclude: Easily exclude specific apps (e.g., Spotify, Discord) from counting toward "Work Time."
- π Anti-Tamper Security:
- Monotonic Clock Protection: Uses unchangeable system clocks to detect time manipulation
- Network Time Sync: Validates against trusted NTP servers to catch clock changes
- Cryptographic Hash Chaining: Links all entries with SHA-256 hashes to prevent retroactive editing
- Trust Scoring: Real-time integrity monitoring with tamper event logging
- πΎ Crash Recovery: If the app closes unexpectedly, your session is saved to an
autosavefolder and can be recovered or viewed later. - π Detailed Reporting:
- View live session stats.
- Export sessions to TXT, JSON, or CSV.
- Bulk export all history to a single CSV file.
- π¨ Modern UI: Clean, light-themed interface inspired by Windows 11 Fluent Design, built with PyQt6.
- πΌοΈ App Icons: Extracts and displays actual executable icons for easy visual identification.
|
Main Tracker Clean tracking interface |
Session Report Detailed breakdown & timeline |
Settings Billing & Config management |
|
|
|
-
Clone the Repository:
git clone https://github.com/yourusername/FocusLog.git cd FocusLog -
Install Dependencies: FocusLog requires
PyQt6,pywin32,psutil, andPillow.pip install PyQt6 pywin32 psutil Pillow
-
Run the Application: You can use the provided batch file for convenience:
run.bat
(Or manually run
python app.py)
If you want to create a single .exe file that doesn't require Python to be installed on the target machine:
-
Install PyInstaller:
pip install pyinstaller
-
Prepare Icon (Optional): Ensure you have an
icon.icofile in the root directory. If you don't have one, you can remove the--icon=icon.icoflag from the build script. -
Run the Build Script: Double-click
build.bator run it in your terminal:build.bat
This script automatically detects your Python installation path using
%APPDATA%, builds the executable, and cleans up temporary files. -
Find your Executable: The resulting
FocusLog.exewill be placed in the root folder.
FocusLog/
βββ icon.ico # Application Icon
βββ app.py # Main UI Entry Point (PyQt6)
βββ tracker.py # Core Logic: Polling loop, state management, crash recovery
βββ report.py # Data formatting, export utilities (CSV/JSON/TXT)
βββ appinfo.py # Windows API wrappers: Get foreground window, extract icons/names
βββ config.py # Configuration helpers: Data directory management
βββ secure_time.py # Anti-tamper security: Monotonic clocks, hash chaining, NTP sync
βββ run.bat # Quick launcher script
βββ build.bat # Automated PyInstaller build script
βββ requirements.txt # Python dependencies
βββ README.md # This file
βββ SECURITY_FEATURES.md # Detailed documentation of anti-tamper protections
FocusLog stores user data in the local app data directory:
%LOCALAPPDATA%\FocusLog (or ~\FocusLog if env var is missing).
FocusLog comes with a default list of system apps to ignore (e.g., explorer.exe, svchost.exe). You can customize this list.
- Open Settings in the app.
- Click "Edit Auto-Exclusions".
- This opens
auto_excluded_apps.txt. - Add or remove
.exenames (one per line). Lines starting with#are comments. - Click "Reload" in Settings to apply changes immediately without restarting.
If an app displays a confusing technical name (e.g., chrome.exe instead of Google Chrome), you can force a friendly name.
- Open Settings.
- Click "Edit Name Overrides".
- Format:
exename=Friendly Namechrome=Google Chrome code=VS Code
Set your currency and hourly rate in the Settings menu.
- Currency Symbol: Choose from USD, EUR, GBP, JPY, etc.
- Hourly Rate: Enter your rate (e.g.,
50.00). - Note: Earnings are calculated based on Counted Work Time only (excluded apps do not earn money).
- Total Session Time: The entire duration from Start to Stop/Pause.
- Counted Work Time: Time spent in apps that are not excluded. This is the basis for earnings calculations.
- Excluded Apps: Apps you have manually or automatically marked as "non-work." They appear in the report but are marked
[EXCLUDED]and do not contribute to earnings.
sessions/: Contains manually saved session reports (.json).autosave/: Contains automatic backups every 10 seconds (configurable) and crash recoveries.- Files prefixed with
auto_: Regular backups. - Files prefixed with
recovery_: Sessions recovered after a crash.
- Files prefixed with
The heart of the application.
AppTrackerClass: Manages the polling thread._poll_loop(): Runs every 1 second (default). Checksget_foreground_app_info().- Crash Recovery: Uses
active_session.jsonto store state. If the app restarts and finds this file, it offers to recover the session.
Handles Windows-specific interactions.
get_foreground_app_info(): Useswin32guiandpsutilto find the active window's PID and executable path.resolve_name(): Tries to get the "File Description" from the EXE version info for a friendly name. Falls back to overrides or filename.get_icon_image(): Extracts the small icon from the EXE usingwin32gui.ExtractIconExand converts it to a PIL Image for PyQt6.
Handles data serialization.
build_report_data(): Aggregates raw tracker data into a structured dictionary.export_csv(): Generates a flat CSV suitable for Excel analysis.save_to_autosave(): Atomic write to prevent corruption during crashes.
- New Export Format: Add a function in
report.py(e.g.,export_pdf) and call it fromapp.py's_exportmethod. - Dark Mode: Currently, the app forces Light Mode via
ctypesinapp.py. To support Dark Mode, you would need to dynamically switch theBG_*color constants and remove theSetPreferredAppMode(3)call.
Q: Why is my timer not updating?
A: Ensure the app has permission to run in the background. Some "Game Modes" or aggressive power savers may pause Python scripts.
Q: How do I stop tracking specific games or social media?
A: Click the "+ Exclude App" button in the main UI while the app is running, or add the .exe name to auto_excluded_apps.txt.
Q: Where are my saved sessions?
A: Click the π (Folder) icon in the top right header to open the Session Manager. You can also open the folder directly via Settings.
Q: Does this send data online?
A: No. FocusLog is 100% offline. All data is stored locally in your %LOCALAPPDATA% folder.
Q: Was AI Used in this Project?
A: Yes Gemini, Claude, Deepseek, QWEN Thank you so much!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
This project is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License.
You are free to:
- Share β copy and redistribute the material in any medium or format.
- Adapt β remix, transform, and build upon the material.
Under the following terms:
- Attribution β You must give appropriate credit, provide a link to the license, and indicate if changes were made.
- NonCommercial β You may not use the material for commercial purposes.
See the LICENSE file for the full legal text.
- Built with Python and PyQt6.
- Icon extraction powered by pywin32 and Pillow.
- Process monitoring via psutil.


