Your Computer Is Busy When You're Not: Building a Desktop Observability Tool with Electron
You close your laptop.
The screen goes dark.
You assume everything stopped.
But what if it didn't?
Maybe Docker is still transferring data.
Maybe Chrome is still downloading something.
Maybe an application is consuming CPU in the background.
Maybe your computer woke up at 3 AM, performed some background work, and went back to sleep.
Most operating systems already expose pieces of this information.
The interesting part is putting those pieces together.
That's what I wanted to explore:
Can we build an observability layer for a desktop computer using Electron?
Not another CPU/RAM widget.
Something that answers:
What is my computer actually doing?
The Idea
Imagine opening your desktop monitoring application and seeing:
TODAY
────────────────────────────────────
Computer active 7h 42m
Idle 1h 13m
Sleep 8h 05m
Network
↓ Download 6.8 GB
↑ Upload 1.2 GB
Top applications
────────────────────────────────────
VS Code 3h 42m
Chrome 2h 18m
Docker 1h 31m
Slack 52m
Network-heavy apps
────────────────────────────────────
Docker 2.4 GB
Chrome 1.8 GB
VS Code 920 MB
Now imagine clicking "What happened while I was away?"
18:42 User became idle
18:51 Screen locked
18:53 Docker network activity
19:07 Background sync completed
19:14 System entered sleep
That's much more interesting than a CPU percentage.
The npm Package That Makes This Easier
Instead of writing native system integrations for everything ourselves, we can start with:
npm install systeminformation
systeminformation provides APIs for system information, CPU, memory, battery, filesystem, network, processes, Docker and more. It also supports Linux, macOS and Windows, although individual APIs have platform-specific support.
For example:
const si = require("systeminformation");
async function getSystemStats() {
const [cpu, memory, battery, network] = await Promise.all([
si.currentLoad(),
si.mem(),
si.battery(),
si.networkStats()
]);
return {
cpu: cpu.currentLoad,
memory: memory.active,
battery: battery.percent,
network
};
}
console.log(await getSystemStats());
Now our Electron main process can periodically collect system information.
Monitoring Network Activity
One of the most useful APIs is:
si.networkStats()
It provides network statistics including received/transmitted bytes and calculated per-second rates. The package calculates rates based on differences between successive calls, so the first call doesn't provide a meaningful rate yet.
A simple monitor:
const si = require("systeminformation");
setInterval(async () => {
const stats = await si.networkStats();
for (const network of stats) {
console.log({
interface: network.iface,
download: network.rx_sec,
upload: network.tx_sec
});
}
}, 1000);
Now we have something like:
Wi-Fi
Download: 2.4 MB/s
Upload: 180 KB/s
But this is only the beginning.
Network Connections
We can also inspect active network connections:
const connections = await si.networkConnections();
console.log(connections);
This gives us information about active TCP/UDP connections.
That means we can potentially build:
Active Connections
────────────────────────────
TCP 443 api.example.com
TCP 443 github.com
TCP 443 google.com
UDP 53 DNS
Now the dashboard starts becoming useful for troubleshooting.
Which Application Is Active?
Network traffic alone doesn't tell us who is responsible.
We also want to know which application the user is interacting with.
One option is a native active-window module such as:
npm install @jannchie/active-window
The package exposes information about the currently selected window and user idle time on supported Windows, macOS and Linux/Xorg environments. Platform coverage isn't identical everywhere, so this should be treated as an OS-dependent component.
Conceptually:
const activeWindow = require("@jannchie/active-window");
async function getActiveApp() {
const window = await activeWindow().getActiveWindow();
return {
process: window.windowClass,
title: window.windowName
};
}
Then we can record:
10:32:14 VS Code
10:32:15 VS Code
10:32:16 VS Code
...
10:45:02 Chrome
10:45:03 Chrome
Instead of storing every second individually, we can aggregate this into sessions.
VS Code
10:32 → 10:45
Duration: 13 minutes
Sleep and Wake
This is where Electron itself becomes useful.
Electron provides the powerMonitor module for monitoring system power-state changes, including suspend/resume, AC/battery changes, idle state and lock/unlock events on supported platforms.
In the Electron main process:
const { powerMonitor } = require("electron");
powerMonitor.on("suspend", () => {
console.log("System is going to sleep");
});
powerMonitor.on("resume", () => {
console.log("System woke up");
});
We can turn those events into database records:
function recordEvent(type) {
db.insert({
type,
timestamp: new Date()
});
}
powerMonitor.on("suspend", () => {
recordEvent("system_sleep");
});
powerMonitor.on("resume", () => {
recordEvent("system_wake");
});
Now our timeline knows when the machine slept.
Idle Detection
Electron also provides:
powerMonitor.getSystemIdleTime()
and:
powerMonitor.getSystemIdleState(60)
The latter can return states such as active, idle, or locked on supported systems.
For example:
const state = powerMonitor.getSystemIdleState(60);
const idleSeconds = powerMonitor.getSystemIdleTime();
console.log({
state,
idleSeconds
});
We can therefore distinguish:
Active
↓
Idle
↓
Locked
↓
Sleep
That's much more meaningful than simply measuring application runtime.
Putting Everything Together
Now imagine collecting events from four sources:
Electron App
│
┌──────────────┼──────────────┐
│ │ │
powerMonitor systeminformation active-window
│ │ │
│ CPU / RAM / Net Active App
│ │ │
└──────────────┼──────────────┘
▼
Event Collector
│
▼
Local Database
│
▼
Activity Timeline
A simple event model could be:
{
timestamp: Date.now(),
type: "network",
app: "docker",
downloadBytes: 1824000,
uploadBytes: 420000
}
Or:
{
timestamp: Date.now(),
type: "power",
state: "sleep"
}
Or:
{
timestamp: Date.now(),
type: "application",
app: "Code",
window: "server.js - Visual Studio Code"
}
Now everything becomes queryable.
The Interesting Part: Correlation
This is where a normal system monitor becomes a desktop observability tool.
Suppose we see:
18:20 User idle
18:23 CPU 65%
18:24 Network 18 MB/s
18:26 Docker active
18:31 420 MB downloaded
18:42 Screen locked
18:45 Network still active
19:02 System sleep
We can generate an explanation:
Docker continued running after the user became idle and transferred approximately 420 MB before the system entered sleep.
That's an insight.
Not just a metric.
A Simple Collector
We could start with something surprisingly small:
const { powerMonitor } = require("electron");
const si = require("systeminformation");
async function collect() {
const [cpu, memory, network] = await Promise.all([
si.currentLoad(),
si.mem(),
si.networkStats()
]);
return {
timestamp: Date.now(),
system: {
idle: powerMonitor.getSystemIdleTime(),
idleState: powerMonitor.getSystemIdleState(60),
battery: powerMonitor.isOnBatteryPower()
},
cpu: cpu.currentLoad,
memory: {
active: memory.active,
total: memory.total
},
network: network.map(n => ({
interface: n.iface,
rxPerSecond: n.rx_sec,
txPerSecond: n.tx_sec
}))
};
}
setInterval(async () => {
console.log(await collect());
}, 5000);
Five seconds later, we have the beginning of our own desktop telemetry system.
But Don't Collect Everything Every Second
This is an important design decision.
You don't necessarily want:
Every 1 second
↓
Everything
↓
Database
That can generate enormous amounts of useless data.
Instead, use different collection intervals.
Power events Event-driven
App changes Event-driven
CPU 5-10 seconds
Memory 10 seconds
Network 1-5 seconds
Connections 10-30 seconds
Daily aggregates 1 minute+
And store state changes rather than repeated identical states.
For example, don't write:
10:00 VS Code
10:01 VS Code
10:02 VS Code
10:03 VS Code
10:04 VS Code
Store:
VS Code
10:00 → 10:04
Duration: 4 minutes
This makes the database dramatically smaller.
What About Electron's Network Logging?
If the thing you're monitoring is specifically your Electron application's own network traffic, Electron has another useful tool: netLog.
const { app, netLog } = require("electron");
app.whenReady().then(async () => {
await netLog.startLogging("/tmp/electron-network-log");
});
Electron's netLog records network events for a session and supports different capture modes. Be careful with includeSensitive and everything, because those modes can capture sensitive information or transferred bytes.
This is different from systeminformation:
systeminformation
↓
Whole-system information
Electron netLog
↓
Your Electron application's network activity
That distinction is important.
The Product I Would Build
I wouldn't call this another "Task Manager."
I'd call it something like:
Desktop Observability
The dashboard could have four major views.
1. Activity
VS Code 4h 12m
Chrome 2h 31m
Slack 58m
Docker 1h 42m
2. Network
Download 8.4 GB
Upload 1.3 GB
Docker 3.1 GB
Chrome 2.7 GB
VS Code 1.2 GB
3. Power
Active 8h 21m
Idle 1h 08m
Sleep 7h 42m
Battery used 34%
4. Timeline
09:02 Wake
09:05 VS Code
10:32 Chrome
12:14 Idle
12:31 Docker network activity
13:02 Active
18:42 Lock
19:01 Sleep
And then the killer feature:
Ask the computer
Why was my laptop slow today?
What used the most bandwidth?
What happened while I was away?
Which applications are active in the background?
Did anything continue running after I locked the computer?
The Architecture
A practical first version could be:
Electron
│
├── Main Process
│ │
│ ├── powerMonitor
│ ├── systeminformation
│ ├── active-window
│ └── netLog
│
├── Collector
│ │
│ ├── power events
│ ├── app sessions
│ ├── CPU/memory
│ └── network stats
│
├── SQLite
│
└── React Renderer
│
├── Dashboard
├── Timeline
├── Applications
├── Network
└── Power
The key design principle is:
Collect locally. Correlate locally. Explain locally.
You don't need to send a user's entire computer activity to a cloud server just to tell them why their laptop was busy.
The Bigger Idea
The interesting thing here isn't systeminformation.
It isn't Electron's powerMonitor.
It isn't network monitoring.
It's the combination.
A computer is already generating thousands of signals:
Applications
Processes
CPU
Memory
Network
Power
Sleep
Wake
Idle
Lock
Unlock
Today, these signals are mostly presented independently.
A desktop observability layer could connect them.
And instead of asking:
"What's my CPU usage?"
we can finally ask:
"What happened on my computer while I wasn't looking?"
That's a much more interesting monitoring problem.

