WindowLogger is a local Windows activity-tracking tool that records which application window is in the foreground and turns that history into an Excel usage report. It is intended for people who want an evidence-based view of how they spend time across projects, tools, communication, administration, and personal activities.
All collection and analysis happens on the local computer. WindowLogger does not upload activity data to a server.
WindowLogger answers practical questions such as:
- Which applications consumed most of the day?
- How much time was active work versus idle time?
- How was time divided between development, communication, document work, or custom business categories?
- Which window titles are not yet covered by the current classification rules?
- How did application usage differ by day?
It records changes to the foreground window, the executable name, active or inactive status, and explicit logger-session boundaries. The analyser then applies configurable matching rules and produces an .xlsx workbook.
Window titles can contain document names, website titles, customer names, or other sensitive text. Review and protect
WindowLogger.dband exported CSV files as you would any other personal activity record.
- Local and private: no cloud account or external telemetry is required.
- Unified control: one WPF control center starts, pauses, resumes, and stops tracking while exposing recent activity, reports, rules, diagnostics, and settings.
- Privacy on demand: pause tracking during sensitive or personal activity without terminating the logger.
- Accurate session accounting: shutdown and restart boundaries prevent offline time from being counted as usage.
- Reliable long-term storage: SQLite provides indexed date queries, atomic writes, and consistent reports while collection continues.
- Portable history: activity can be exported to or restored from the original CSV format.
- Flexible classification: applications can be matched by one or more title or executable keywords and assigned to multiple categories.
- Actionable reports: Excel output includes category, application, undefined-window, and daily-window views.
- Interactive analytics: inspect day, week, or month timelines and drill from categories into applications and exact window titles before exporting a report.
- Easy refinement: unmatched windows reveal which configuration rules should be added next.
- Portable deployment: the installer includes the required .NET runtime.
| Component | Purpose |
|---|---|
WindowLoggerConfigGui.exe |
Unified WPF control center and recommended entry point. |
WindowLoggerTray.exe |
Optional legacy notification-area controller. |
WindowLogger.exe |
Background foreground-window and inactivity collector. |
WindowAnalyser.exe |
SQLite/CSV analyser, portability utility, and Excel report generator. |
appsettings.json |
Classification and exclusion rules used by the analyser. |
Download WindowLogger-Setup-<version>.exe from GitHub Releases and run it.
The installer:
- installs the self-contained application under
%LOCALAPPDATA%\Programs\WindowLogger; - optionally starts the control center whenever the current user signs in;
- offers to launch the control center when setup finishes.
Open WindowLogger Control Center and use the Dashboard's Start, Pause/Resume, and Stop controls. The dashboard shows current status and recent activity while the background logger writes atomically to WindowLogger.db.
Choose Pause Logging before sensitive or personal activity. While paused, the logger process stays available but does not inspect or record foreground windows. Choose Resume Logging to continue collection. Pause and resume create separate session boundaries, so the paused interval is excluded from reports.
Choose Stop Logging before moving or backing up the database itself. Normal shutdown records a session boundary so time between logger runs is not included in reports.
Open the Applications, Exclusions, and Categories tabs in the control center.
- Applications map window-title or executable keywords to a friendly application name.
- Exclusions remove matching windows from all calculations.
- Categories group named applications into broader areas such as Development, Communication, or Finance.
- Application rules are evaluated in order, so place specific rules before broad fallback rules.
Use Undefined Applications in a generated report to discover titles that need new rules. Advanced users can choose Edit Configuration (JSON) instead.
Use the Diagnostics tab to find duplicate definitions, unreachable rules, include/exclude conflicts, empty categories, and applications that have never matched recorded history.
Use Rule Tester before saving classification changes:
- enter a window title and executable separately, or select a recently recorded captured value;
- preview the exact
Window title [executable.exe]value used by reports; - see whether a global exclusion wins, which first matching application is selected, and every assigned category;
- inspect an ordered trace showing each matched or failed include/exclude pattern and any shadowed application rules;
- jump directly to the matched application or category, create a starter application rule from the sample, or copy the captured value;
- test the current unsaved editor draft, including reordered and newly added rules.
The tester also stores editable regression cases in the optional RuleTests section of appsettings.json. Each case records its sample and expected exclusion, application, and comma-separated categories. Run All updates pass/fail results, and saving configuration warns before continuing if any stored expectation fails.
The analyser, interactive timeline, and Rule Tester use the same shared evaluation engine, so preview precedence and matching behavior are identical to generated reports.
Open Timeline & Analytics to explore activity without generating a workbook:
- switch among day, week, and month periods and navigate backward or forward;
- distinguish active and idle blocks on the proportional timeline;
- compare total time and every category/application with the immediately preceding equivalent period;
- search across category names, applications, and raw window titles;
- filter the view to active or inactive time;
- select a category to filter applications, then select an application to inspect its window-title breakdown.
For the current day, week, or month, comparisons use the same elapsed portion of the previous period rather than comparing a partial current period with a complete previous one.
Choose Generate Report on the Dashboard. WindowLogger reads a consistent SQLite snapshot—even while collection continues—creates a timestamped workbook in the configured report folder, and opens it with the system's associated spreadsheet application.
The workbook contains:
- Categories — total active and inactive time per configured category.
- Applications — total time per matched application.
- Undefined Applications — unmatched titles for configuration refinement.
- Windows — daily window-level totals.
Choose Export Activity to CSV for a portable backup or Import Activity from CSV to replace the current history. Import temporarily stops collection and restores its previous running or paused state afterward.
Choose Clear Collected Data to stop the logger, remove the current SQLite database, and restart collection if it was previously active. If tracking was paused, it restarts in the paused state. This action cannot be undone.
For an installer-based deployment, the application files and writable data are stored together by default:
%LOCALAPPDATA%\Programs\WindowLogger\
├── WindowLogger.db
├── WindowLogger.settings.json
├── appsettings.json
├── Report.xlsx
└── application executables and runtime files
| File | Contents |
|---|---|
WindowLogger.db |
Indexed SQLite history containing foreground-window, status, and session events. |
WindowLogger.settings.json |
User-editable tracking, privacy, retention, report-folder, recovery, and startup preferences. |
appsettings.json |
Application matching, exclusions, and categories. |
Report.xlsx |
Most recently generated analysis workbook. |
Requirements: Windows and the .NET 10 SDK.
dotnet build WindowLogger.sln --configuration Release
dotnet test WindowLogger.sln --configuration Release
dotnet run --project WindowLoggerConfigGui\WindowLoggerConfigGui.csprojTo build the installer locally, install Inno Setup 6 and run:
.\Installer\Build-Installer.ps1 -Version 1.2.3See Installer/README.md for release-tag and packaging details.
If you prefer to run components manually without the Control Center:
Running the Logger:
dotnet WindowLogger.dllRunning the Analyser:
dotnet WindowAnalyser.dll WindowLogger.db Report.xlsxThe logger automatically imports a legacy WindowLogger.csv when it creates an empty database, then renames the source to WindowLogger.migrated-<timestamp>.csv so it cannot be imported twice.
If a crash or forced termination leaves a session open, the next logger start inserts a conservative session end capped by CrashRecoveryMaxMinutes. This prevents the unknown time until restart from being attributed to the last active window.
Use the Privacy & Settings tab to configure inactivity and polling intervals, title storage, initial paused state, retention days, crash-recovery cap, report folder, automatic tracking, and launch-at-sign-in. Saving settings applies retention immediately and restarts an owned logger so timing and privacy changes take effect safely.
CSV imports and exports contain three columns:
Timestamp,Window Title [Executable],Status
Example Content:
2026-01-18 09:15:00,,SessionStart
2026-01-18 09:15:30,Visual Studio 2022 [devenv.exe],Active
2026-01-18 09:20:45,Google Chrome - GitHub [chrome.exe],Active
2026-01-18 09:25:10,Slack - Development Team [slack.exe],Active
2026-01-18 09:30:00,Slack - Development Team [slack.exe],Inactive
2026-01-18 09:31:15,Visual Studio 2022 [devenv.exe],Active
2026-01-18 10:00:00,,SessionEndStatus Values:
Active- User is actively using the computerInactive- No user input detected for 1+ minute (configurable)SessionStart- A new logger process began; no time is attributed across this boundarySessionEnd- The logger stopped normally and closes the final usage interval
File Name: appsettings.json
Location: Same directory as WindowAnalyser.exe
The configuration file must be in:
WindowAnalyser/bin/Debug/net10.0/appsettings.json
The project is already configured to copy this file to the output directory automatically.
The generated Excel workbook contains 4 worksheets:
- Categories: Aggregates time by your defined categories (e.g., "Productivity", "Social").
- Applications: Aggregates time by defined application names.
- Undefined Applications: Shows windows that didn't match any rule (useful for refining config).
- Windows: Daily breakdown of all raw window activity.
Time Columns: The report includes precise time tracking: Time Spent (Hours) | Time Spent (Minutes)
- Real-time Window Tracking: Monitors the foreground window every 500ms
- Executable Detection: Records both window title and process name
- Inactivity Detection: Automatically detects when user is idle (default: 1 minute)
- Durable Logging: Writes atomic SQLite transactions in WAL mode, allowing reports and exports during collection
- Polls the foreground window every 500 milliseconds
- Detects window changes and logs them with timestamp
- Monitors user input (keyboard/mouse) to detect inactivity
- When inactive for 1 minute, logs "Inactive" status
- When activity resumes, logs "Active" status with new window
Edit constants in WindowLogger/Program.cs:
private static readonly TimeSpan InactivityThreshold = TimeSpan.FromMinutes(1);Change the polling interval (default: 500ms):
private static readonly TimeSpan PollInterval = TimeSpan.FromMilliseconds(500);Option 1: Start Minimized
- Create a shortcut to
WindowLogger.exe - Right-click → Properties → Run: Minimized
Option 2: Windows Task Scheduler
- Schedule to run at login
- Run whether user is logged on or not
- Configure to restart on failure
WindowAnalyser.exe <input-db-or-csv-file> <output-xlsx-file>
WindowAnalyser.exe export <input-db-file> <output-csv-file> [--from <date>] [--to <exclusive-date>]
WindowAnalyser.exe import <input-csv-file> <output-db-file> [--replace]Parameters:
input-db-or-csv-file- Path to the SQLite database or a portable legacy CSV exportoutput-xlsx-file- Desired path/name for the Excel report--from/--to- Optional indexed export range; the lower bound is inclusive and upper bound exclusive--replace- Atomically replaces the destination database contents during import
Examples:
# Absolute paths
WindowAnalyser.exe C:\Logs\WindowLogger.db C:\Reports\weekly_report.xlsx
# Relative paths
WindowAnalyser.exe WindowLogger.db report.xlsx
# Portable backup and restore
WindowAnalyser.exe export WindowLogger.db backup.csv
WindowAnalyser.exe import backup.csv restored.db --replace
# Analyze multiple periods
WindowAnalyser.exe logs\january.csv reports\january_analysis.xlsx
WindowAnalyser.exe logs\february.csv reports\february_analysis.xlsxThe output workbook contains 4 worksheets:
Groups time by configured categories (e.g., "Productivity", "Development")
| Category | Status | Time Spent (Minutes) | Time Spent (Hours) |
|---|---|---|---|
| Development | Active | 240.5 | 4.01 |
| Communication | Active | 95.2 | 1.59 |
| Productivity | Inactive | 15.0 | 0.25 |
Groups time by configured application names
| Application | Status | Time Spent (Minutes) | Time Spent (Hours) |
|---|---|---|---|
| Visual Studio | Active | 180.3 | 3.01 |
| Browser | Active | 120.5 | 2.01 |
| Slack | Active | 45.2 | 0.75 |
Shows windows that didn't match any application rule - use this to identify applications you should add to your configuration
| Window | Status | Time Spent (Minutes) | Time Spent (Hours) |
|---|---|---|---|
| Calculator [calc.exe] | Active | 25.5 | 0.43 |
| Notepad++ [notepad++.exe] | Active | 18.2 | 0.30 |
Daily breakdown of all window activity
| Date | Window | Status | Time Spent (Minutes) | Time Spent (Hours) |
|---|---|---|---|---|
| 2026-01-18 | Visual Studio | Active | 120.5 | 2.01 |
| 2026-01-18 | Chrome | Active | 65.3 | 1.09 |
| 2026-01-19 | Visual Studio | Active | 180.0 | 3.00 |
-
First Run - Without
appsettings.jsonWindowAnalyser.exe WindowLogger.csv initial_report.xlsx
- All windows appear in "Undefined Applications" tab
- No categories are generated
-
Review Undefined Applications
- Open the Excel report
- Check the "Undefined Applications" tab
- Identify which windows you want to track
-
Configure Application Rules
- Edit
appsettings.jsonin the WindowAnalyser directory - Add application definitions based on window titles
- Define categories for grouping
- Edit
-
Re-run Analysis
WindowAnalyser.exe WindowLogger.csv categorized_report.xlsx
- Applications now appear in "Applications" tab
- Categories are populated
- "Undefined Applications" shows only unmatched windows
-
Iterate
- Continue refining rules until most windows are categorized
- Run analysis periodically (daily/weekly) to track trends
The appsettings.json file controls how window titles are classified.
{
"applications": [ ... ],
"exclusions": [ ... ],
"categories": [ ... ]
}Define how window titles map to logical application names.
Properties:
name- Logical application name (appears in report)include- Keywords that must all appear in the window titleexclude- Keywords that must not appear (optional)
Example:
{
"name": "Browser",
"include": [ "Firefox" ],
"exclude": [ "taskbeat" ]
}Matching Rules:
- All
includekeywords must be present (AND logic) - Any
excludekeyword disqualifies the match - Matching is case-insensitive
- First match wins - order matters!
Best Practices:
- Specific rules first, generic rules last:
{
"applications": [
{
"name": "Notepad - MyTask",
"include": [ "Notepad", "MyTask.txt" ],
"exclude": []
},
{
"name": "Notepad",
"include": [ "Notepad" ],
"exclude": [ "MyTask.txt" ]
}
]
}- Use executable names for precision:
{
"name": "Visual Studio",
"include": [ "Visual Studio", "devenv.exe" ],
"exclude": []
}- Group similar browsers:
[
{
"name": "Browser",
"include": [ "Firefox" ],
"exclude": []
},
{
"name": "Browser",
"include": [ "Chrome" ],
"exclude": []
},
{
"name": "Browser",
"include": [ "Edge" ],
"exclude": []
}
]Define window titles to completely remove from analysis.
Example:
{
"exclusions": [
{
"include": [ "Firefox", "ebay", "cart" ]
},
{
"include": [ "private", "browsing" ]
}
]
}When a window matches an exclusion rule:
- It's removed from all reports
- Time is not counted anywhere
- It's as if the window never existed
Use Cases:
- Exclude personal browsing during work hours
- Filter out sensitive/private windows
- Remove testing/debugging windows
Group applications into higher-level categories for aggregate reporting.
Properties:
name- Category name (appears in report)includeApplications- Application names to includeexcludeApplications- Applications to exclude (optional)
Example:
{
"categories": [
{
"name": "Development",
"includeApplications": [ "Visual Studio", "VS Code", "Terminal" ],
"excludeApplications": []
},
{
"name": "Productivity",
"includeApplications": [ "Notepad", "TaskBeat" ],
"excludeApplications": [ "Notepad - MyTask" ]
},
{
"name": "Communication",
"includeApplications": [ "Slack", "Teams", "Outlook" ],
"excludeApplications": []
}
]
}Important:
- Applications can belong to multiple categories
- Time is counted separately for each category (can exceed 100%)
- Use
excludeApplicationsto create exceptions within broader groups
{
"applications": [
{
"name": "Visual Studio",
"include": [ "Visual Studio" ],
"exclude": []
},
{
"name": "VS Code",
"include": [ "Visual Studio Code" ],
"exclude": []
},
{
"name": "Browser",
"include": [ "Firefox" ],
"exclude": [ "taskbeat" ]
},
{
"name": "TaskBeat",
"include": [ "Firefox", "taskbeat" ],
"exclude": []
},
{
"name": "Slack",
"include": [ "Slack" ],
"exclude": []
},
{
"name": "Notepad - MyTask",
"include": [ "Notepad", "MyTask.txt" ],
"exclude": []
},
{
"name": "Notepad",
"include": [ "Notepad" ],
"exclude": [ "MyTask.txt" ]
}
],
"exclusions": [
{
"include": [ "Firefox", "ebay", "cart" ]
}
],
"categories": [
{
"name": "Development",
"includeApplications": [ "Visual Studio", "VS Code" ],
"excludeApplications": []
},
{
"name": "Communication",
"includeApplications": [ "Slack" ],
"excludeApplications": []
},
{
"name": "Productivity",
"includeApplications": [ "Notepad", "TaskBeat" ],
"excludeApplications": [ "Notepad - MyTask" ]
},
{
"name": "MyTask",
"includeApplications": [ "Notepad - MyTask" ],
"excludeApplications": []
}
]
}- Operating System: Windows (uses Win32 APIs for window tracking)
- .NET Runtime: .NET 10.0 or higher
- Desktop UI: Windows Presentation Foundation (WPF)
- Excel Viewer: Microsoft Excel or compatible spreadsheet application
WindowLogger:
- Microsoft.Data.Sqlite and SQLitePCLRaw for durable embedded storage
WindowAnalyser:
- ClosedXML (0.105.0-rc) - for Excel generation
- Microsoft.Data.Sqlite - for concurrent SQLite snapshot reads and CSV portability operations
- System.Text.Json (included with .NET) - for configuration parsing
- Run Continuously: Leave WindowLogger running all day for accurate tracking
- Regular Analysis: Analyze logs daily or weekly to identify patterns
- Backup Activity: Use Export Activity to CSV for portable backups while collection continues
- Retain History: Keep the SQLite database for efficient long histories and use date-bounded CLI exports when needed
- Start Simple: Begin with broad application categories
- Refine Gradually: Add more specific rules as you identify patterns
- Use Undefined Tab: Regularly check "Undefined Applications" to find unmatched windows
- Test Rules: Re-run analysis after configuration changes to verify rules work as expected
- Document Rules: Add comments (not supported in JSON, but keep notes separately) about why specific rules exist
- Compare Periods: Generate reports for different time periods to track changes
- Focus on Active Time: Filter by "Active" status to see productive time
- Review Inactive Patterns: High inactive time may indicate distractions or away-from-desk time
- Category Overlaps: Remember that categories can overlap - total category time may exceed 100%
Cause: Configuration file is missing or has invalid JSON
Solution:
- Ensure
appsettings.jsonexists in the same directory asWindowAnalyser.exe - Validate JSON syntax using a JSON validator
- The analyzer will use default settings (no grouping) if the file is invalid
Cause: Log file is corrupted or has an unexpected format
Solution:
- Check that the CSV file was exported by WindowLogger or uses its three-column legacy format
- Ensure the file hasn't been manually edited with incorrect formatting
- Verify the file isn't empty
Cause: No windows matched your application rules
Solution:
- Check the "Undefined Applications" tab to see what windows were logged
- Add application rules to
appsettings.jsonmatching those window titles - Re-run the analysis
Cause: Running continuously for extended periods
Solution:
- Export the desired date ranges to CSV for archival
- Keep a backup before clearing collected data
- Use Clear Collected Data to start a new database while preserving the logger's running or paused state
This project is open source and available under the repository license.