← Back to all projects

LEARN MACOS MONITORING APIS

Learn macOS Monitoring APIs: From Zero to Activity Tracking Master

Goal: Deeply understand the macOS APIs that allow applications like RescueTime and Pieces to monitor system activity, from the current application and window title to keyboard events and clipboard content.


Why Learn macOS Monitoring?

Modern productivity and developer tools often rely on understanding user context. They passively observe activity to provide insights, automate workflows, or capture valuable information. Building these tools requires a deep dive into macOS frameworks that are often poorly documented and guarded by strict privacy permissions.

After completing these projects, you will:

  • Know how to identify the active application and its windows.
  • Use the Accessibility API to read UI elements from other apps.
  • Monitor global keyboard and mouse events securely.
  • Capture clipboard content.
  • Understand the powerful (and sensitive) nature of system-wide monitoring and the importance of user privacy.

Core Concept Analysis

macOS provides several distinct APIs for observing system state. Each is designed for a specific purpose and requires explicit user consent.

┌──────────────────────────────────────────────────────────────────────────────┐
│                                 Your Application                               │
└──────────────────────────────────────────────────────────────────────────────┘
                                        │
     ┌──────────────────────────────────┼──────────────────────────────────┐
     │                                  │                                  │
     ▼                                  ▼                                  ▼
┌────────────────────┐      ┌──────────────────────────┐      ┌────────────────────────┐
│ NSWorkspace        │      │ Accessibility API (AX)   │      │ CoreGraphics Event Taps│
│                    │      │                          │      │                        │
│ • Get active app   │      │ • Read window titles     │      │ • Global key/mouse     │
│ • List running apps│      │ • Get UI element values  │      │   listeners (e.g. Cmd+C) │
│                    │      │ • Get browser URLs       │      │                        │
│ Permission: None   │      │                          │      │ Permission:            │
│ (App Sandbox)      │      │ Permission: Accessibility│      │ Input Monitoring       │
└────────────────────┘      └──────────────────────────┘      └────────────────────────┘
             │                        │                                  │
             └───────────────┬────────┴───────────────┐                  │
                             │                        │                  │
                             ▼                        ▼                  ▼
              ┌────────────────────────┐  ┌────────────────────────┐  ┌────────────────────┐
              │ NSPasteboard           │  │ FSEvents / FileProvider│  │ EndpointSecurity   │
              │                        │  │                        │  │                    │
              │ • Read clipboard       │  │ • Watch for file       │  │ • System-wide      │
              │   content              │  │   changes              │  │   process/file/net │
              │ • Get change count     │  │                        │  │   events           │
              │                        │  │ Permission:            │  │                    │
              │ Permission: None       │  │ Full Disk Access (often) │  │ Permission: Special│
              │                        │  │                        │  │ Entitlement (Apple)│
              └────────────────────────┘  └────────────────────────┘  └────────────────────┘


Project List

These projects are designed to be built in order, as each one introduces a new core concept and often a new user permission you’ll need to handle. The primary language is Swift, the modern standard for macOS development.


Project 1: Active App Menu Bar Ticker

  • File: LEARN_MACOS_MONITORING_APIS.md
  • Main Programming Language: Swift
  • Alternative Programming Languages: Objective-C
  • Coolness Level: Level 2: Practical but Forgettable
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: macOS App Development / AppKit
  • Software or Tool: Xcode
  • Main Book: “Beginning iPhone Development with Swift” by David Mark, Jack Nutting (provides a good foundation for Swift and Apple’s development paradigm, though it’s iOS-focused)

What you’ll build: A simple macOS application that lives in the menu bar. Its icon will change to the icon of the currently active application, and the tooltip will show the active application’s name.

Why it teaches monitoring: This is the “hello world” of activity monitoring. It introduces NSWorkspace, the simplest and safest API for getting system-state information, and teaches the basics of building a background macOS utility.

Core challenges you’ll face:

  • Creating a menu bar app → maps to using NSStatusItem
  • Getting the active application → maps to using NSWorkspace.shared.frontmostApplication
  • Setting up a timer → maps to using Timer to poll for changes periodically
  • Handling application icons → maps to working with NSRunningApplication and NSImage

Key Concepts:

Difficulty: Beginner Time estimate: Weekend Prerequisites: Basic Swift knowledge, Xcode installed.

Real world outcome: A new icon appears in your macOS menu bar. As you switch between applications (e.g., from Finder to Chrome), the icon in the menu bar updates in real-time to match the active app.

Implementation Hints: In your AppDelegate or main app controller:

  1. Create an NSStatusItem in the system status bar.
  2. Set up a Timer to fire every 1 or 2 seconds.
  3. In the timer’s action method, get the frontmostApplication from NSWorkspace.shared.
  4. This NSRunningApplication object has properties like localizedName and icon.
  5. Update the NSStatusItem’s button with the new icon and its toolTip with the name.

Learning milestones:

  1. A menu bar item appears.
  2. The name of the active app can be printed to the console.
  3. The menu bar icon updates when the active app changes.
  4. The app is sandboxed and runs correctly.

Project 2: Window Title Logger

  • File: LEARN_MACOS_MONITORING_APIS.md
  • Main Programming Language: Swift
  • Alternative Programming Languages: Objective-C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Micro-SaaS / Pro Tool”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Accessibility API / Inter-App Communication
  • Software or Tool: Xcode
  • Main Book: N/A (relies on documentation and articles)

What you’ll build: A background utility that logs the window title of the active application every time it changes. For example, it will log the subject of an email, the name of a document in Word, or the title of a webpage.

Why it teaches monitoring: This is the core technique used by apps like RescueTime. It forces you to learn the Accessibility API, a powerful but complex framework that lets your app inspect and control other applications. It also introduces the critical concept of requesting user permissions.

Core challenges you’ll face:

  • Requesting Accessibility permissions → maps to prompting the user and checking status
  • Getting the frontmost window of another app → maps to using AXUIElement to reference another app’s UI
  • Reading the title attribute → maps to querying accessibility attributes of a UI element
  • Handling permissions denial gracefully → maps to guiding the user to System Settings

Resources for key challenges:

Key Concepts:

  • Accessibility (AX) API: The framework for inspecting and controlling other apps.
  • AXUIElement: An accessibility object representing a UI element in another process.
  • Info.plist Privacy Strings: The NSPrivacyAccessedAPICategoryAccessibility key is required to explain why you need the permission.

Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Project 1, understanding of Swift optionals and error handling.

Real world outcome: You’ll have a text file (activity_log.txt) that contains a timestamped list of every window you’ve focused on, providing a raw data source for your computer activity.

Implementation Hints:

  1. First, you must check for and request accessibility permissions using AXIsProcessTrustedWithOptions. This will show a system prompt to the user.
  2. Get the pid (process identifier) of the frontmostApplication.
  3. Create an AXUIElement representing that application using AXUIElementCreateApplication(pid).
  4. From the application element, get the value of the kAXFocusedWindowAttribute.
  5. This gives you another AXUIElement for the window. From this, get the value of kAXTitleAttribute.
  6. This process is “failable” at every step, so use robust error checking.
  7. Combine this with the timer from Project 1 to poll for the title.

Learning milestones:

  1. Your app correctly prompts for Accessibility permissions.
  2. You can get the window title of your own app.
  3. You can get the window title of another app (e.g., TextEdit).
  4. The app logs titles as you switch between different windows and applications.

Project 3: Global Copy & Paste Logger

  • File: LEARN_MACOS_MONITORING_APIS.md
  • Main Programming Language: Swift
  • Alternative Programming Languages: Objective-C, Python (with pyobjc)
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 3. The “Service & Support” Model
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Event Taps / Pasteboard API
  • Software or Tool: Xcode
  • Main Book: N/A

What you’ll build: A background tool that detects every time the user copies text (Cmd+C) and logs that text to a file. This mimics a core feature of Pieces.app.

Why it teaches monitoring: This teaches two distinct but related concepts:

  1. How to listen for global keyboard events using CoreGraphics Event Taps.
  2. How to read data from the system’s shared clipboard (NSPasteboard).

Core challenges you’ll face:

  • Creating a CGEventTap → maps to a low-level C API for intercepting system-wide events
  • Requesting Input Monitoring permissions → maps to another critical privacy permission
  • Interpreting keyboard flags → maps to detecting if the Command key is held down
  • Reading from NSPasteboard → maps to checking for text content and reading it

Resources for key challenges:

Key Concepts:

  • CGEventTapCreate: The C function to create an event listener.
  • Input Monitoring Permission: Required for event taps. Your Info.plist needs NSPrivacyAccessedAPICategoryInputMonitoring.
  • NSPasteboard: The class for interacting with the clipboard.

Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Project 1, some comfort with C-style APIs in Swift.

Real world outcome: A log file (clipboard_history.txt) containing every piece of text you’ve copied. A powerful (and dangerous!) tool that makes the privacy implications of this work very clear.

Implementation Hints:

Part 1: The Event Tap

  1. Set up a CGEventTap for the keyDown event. This requires a C-style callback function.
  2. In the callback, check the event’s keyboard flags to see if the command flag is set.
  3. Check if the keycode is for the ‘c’ key.
  4. If Cmd+C is detected, post a Notification using NotificationCenter.

Part 2: The Pasteboard Listener

  1. In another part of your app, subscribe to the notification from Part 1.
  2. When the notification is received, access NSPasteboard.general.
  3. Check if the pasteboard contains strings (canReadObjects(forClasses: [NSString.self])).
  4. If so, read the string content using string(forType: .string).
  5. Log the content.

This two-part approach decouples the low-level event tap from the higher-level pasteboard logic.

Learning milestones:

  1. Your app prompts for Input Monitoring permissions.
  2. A log message appears in the console every time any key is pressed.
  3. The log is filtered to only show when Cmd+C is pressed.
  4. The copied text is successfully read from the pasteboard and saved.

Project 4: Downloads Folder Watcher

  • File: LEARN_MACOS_MONITORING_APIS.md
  • Main Programming Language: Swift
  • Alternative Programming Languages: C
  • Coolness Level: Level 2: Practical but Forgettable
  • Business Potential: 2. The “Micro-SaaS / Pro Tool”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: File System APIs
  • Software or Tool: Xcode
  • Main Book: “Advanced Programming in the UNIX Environment” by Stevens & Rago (for general filesystem concepts).

What you’ll build: A utility that monitors the ~/Downloads directory and sends a user notification whenever a new file appears.

Why it teaches monitoring: It teaches you how to monitor file system activity efficiently, without manually polling folder contents. This is fundamental for any app that needs to react to file changes (e.g., Dropbox, Hazel, image optimizers).

Core challenges you’ll face:

  • Using the FSEvents API → maps to another C-based API for file system notifications
  • Setting up a stream → maps to defining the path and latency for monitoring
  • Parsing event flags → maps to determining if an event is a file creation, modification, etc.
  • Handling App Sandbox → maps to understanding which directories your app can access

Key Concepts:

  • FSEvents API: The low-level C API for getting file system notifications.
  • FSEventStreamCreate: The core function to start monitoring a path.
  • User Notifications: The UserNotifications framework for displaying alerts to the user.

Difficulty: Intermediate Time estimate: 1 week Prerequisites: Project 1.

Real world outcome: When a file finishes downloading in your browser, a notification immediately appears on your screen: “New file detected: downloaded-image.png”.

Implementation Hints:

  1. Create an FSEventStream that watches the path to ~/Downloads.
  2. You’ll provide a callback function that the system will execute when events occur.
  3. The callback receives the path(s) that changed and flags indicating the type of change.
  4. In your callback, iterate through the events. If you see an ItemCreated flag, you’ve found a new file.
  5. To show a notification, you first need to request permission using UNUserNotificationCenter.current().requestAuthorization.
  6. Then, construct and submit a UNNotificationRequest.

Learning milestones:

  1. An FSEventStream is successfully created and started.
  2. The callback fires when you manually create a file in the Downloads folder.
  3. Your app can distinguish between file creation and modification events.
  4. A user notification is displayed for new files.

Project 5: The Ultimate Challenge - Endpoint Security Process Monitor

  • File: LEARN_MACOS_MONITORING_APIS.md
  • Main Programming Language: Swift/C
  • Alternative Programming Languages: N/A (requires tight OS integration)
  • Coolness Level: Level 5: Pure Magic (Super Cool)
  • Business Potential: 4. The “Open Core” Infrastructure
  • Difficulty: Level 5: Master
  • Knowledge Area: System Internals / Security
  • Software or Tool: Xcode, Apple Developer Account
  • Main Book: “macOS Internals” (online resources are more current)

What you’ll build: A command-line tool that logs every time a new process starts running on your system, anywhere. It will show the process name and its PID.

Why it teaches monitoring: This is the deepest level of monitoring possible on modern macOS without writing a kernel extension. It introduces the Endpoint Security framework, the official tool for antivirus and EDR (Endpoint Detection and Response) software.

Core challenges you’ll face:

  • Requesting a special entitlement → maps to you must apply to Apple for permission to use this framework
  • Creating an Endpoint Security client → maps to subscribing to system-wide event streams like process execution
  • Handling C structs and pointers extensively → maps to these are low-level C APIs with no Swift overlays
  • Building a System Extension → maps to the modern way to deploy background daemons that use this framework

Resources for key challenges:

Key Concepts:

  • Endpoint Security: The framework for system-wide security monitoring.
  • System Extension: The modern replacement for kernel extensions.
  • Entitlements: Special permissions granted by Apple that are baked into your app’s signature.

Difficulty: Master Time estimate: 1 month+ Prerequisites: Strong C and Swift skills, understanding of system architecture, and a paid Apple Developer account.

Real world outcome: When you run your tool, you’ll see a real-time stream of every process starting on your Mac, from the tiny background daemons to the applications you launch.

$ sudo ./process_monitor
EXEC: /bin/ls (PID: 50123)
EXEC: /usr/bin/grep (PID: 50124)
EXEC: /Applications/Calculator.app/Contents/MacOS/Calculator (PID: 50126)
...

Implementation Hints:

  1. This is a huge undertaking. The first step is to apply for the Endpoint Security entitlement from Apple.
  2. Once granted, you’ll create a new “System Extension” target in Xcode.
  3. The core of your code will be creating an es_client_t and subscribing to events, specifically ES_EVENT_TYPE_NOTIFY_EXEC.
  4. Your event handler will receive an es_message_t containing information about the process. You’ll need to parse this C struct to get the executable path and PID.
  5. Because this is a privileged operation, your tool will need to be installed and run with root permissions.

Learning milestones:

  1. Your entitlement request is approved by Apple.
  2. You can build and install a simple System Extension.
  3. Your client successfully subscribes to the event stream.
  4. You can correctly parse an es_message_t and log process execution events.

Summary

Project Main Language Difficulty Core API
1. Active App Menu Bar Ticker Swift Beginner NSWorkspace
2. Window Title Logger Swift Advanced Accessibility
3. Global Copy & Paste Logger Swift Advanced CGEventTap, NSPasteboard
4. Downloads Folder Watcher Swift Intermediate FSEvents
5. Endpoint Security Monitor Swift/C Master EndpointSecurity