Every time you press ⌘C on a Mac, you're interacting with NSPasteboard — the AppKit class that has powered copy and paste on macOS since the NeXTSTEP days. It's one of the oldest APIs in the system, and it's deceptively simple on the surface. But underneath, there's a surprisingly rich data model that most developers never explore.
If you've ever wondered how clipboard managers detect new copies, how a single copy operation can carry both plain text and rich text simultaneously, or why there's no notification API for clipboard changes — this is the deep dive.
What is NSPasteboard?
NSPasteboard is a shared, system-wide data broker. When an app copies data, it writes one or more representations of that data to a pasteboard. When another app pastes, it reads the representation it prefers. The pasteboard is the intermediary — the two apps never communicate directly.
The API is straightforward. Writing looks like this:
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.setString("Hello, world", forType: .string)
Reading is equally simple:
if let string = NSPasteboard.general.string(forType: .string) {
print(string)
}
But this simplicity hides the real power of the system — multiple types, multiple items, and lazy data providing.
Pasteboard types
macOS has several distinct pasteboards, each serving a different purpose:
For clipboard management, only NSPasteboard.general matters. But the find pasteboard is worth knowing about — it's one of macOS's best hidden features.
UTIs and data representation
When you copy formatted text from a web page, the pasteboard doesn't just store one thing. It stores multiple representations of the same content — HTML, RTF, plain text, and sometimes more. The pasting app chooses which representation to use.
These representations are identified by Uniform Type Identifiers (UTIs), now formalized as UTType in the UniformTypeIdentifiers framework. Common ones include:
public.utf8-plain-text— plain textpublic.html— HTML markuppublic.rtf— Rich Text Formatpublic.png— PNG image datapublic.file-url— file path as a URL
A single copy operation can place a dozen different representations on the pasteboard. The pasting app picks the richest format it understands.
This is why pasting into a code editor gives you plain text while pasting into Pages gives you formatted text — same pasteboard data, different type preference.
Change count and monitoring
Here's the critical detail for clipboard manager developers: macOS has no notification API for pasteboard changes. There's no NSNotification, no delegate callback, no Combine publisher. The only way to know the clipboard changed is to poll.
NSPasteboard.general.changeCount is an integer that increments every time the pasteboard contents change. A clipboard manager's core loop looks like this:
var lastChangeCount = NSPasteboard.general.changeCount
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
let current = NSPasteboard.general.changeCount
if current != lastChangeCount {
lastChangeCount = current
// New clipboard content — read and store it
}
}
Change count behavior
The change count also increments when clearContents() is called, even if no new data is written. Clipboard managers need to handle the case where the pasteboard was cleared but has no readable content. Always check for valid data after detecting a change.
The polling interval is a tradeoff. Too fast and you waste CPU. Too slow and the user copies something, pastes it, and the manager never saw it. Most clipboard managers — including QuietClip — poll every 0.3 to 0.5 seconds. The CPU cost is negligible since checking changeCount is a single integer comparison.
Multiple items on the pasteboard
NSPasteboard can hold multiple items simultaneously, each with its own set of type representations. This is most commonly used during drag-and-drop — select ten files in Finder, drag them, and the pasteboard contains ten items, each with a file URL.
let items = NSPasteboard.general.pasteboardItems ?? []
for item in items {
for type in item.types {
print("Type: \(type.rawValue)")
}
}
For clipboard managers, multi-item pasteboards need special handling. When a user copies ten files, you probably want to store that as a single history entry — not ten separate ones.
How clipboard managers use NSPasteboard
A clipboard manager like QuietClip builds on everything above. The core workflow is:
- Poll
changeCounton a timer - When it changes, read all available types from the pasteboard
- Store the data persistently (QuietClip uses SwiftData)
- When the user wants to re-paste an old item, write it back to the pasteboard
- Simulate ⌘V using CGEvent to paste it into the active app
Step 5 is why clipboard managers need Accessibility permissions — they're synthesizing keystrokes. But the pasteboard reading itself requires no special permissions. Any app can read NSPasteboard.general at any time.
Because any app can read the clipboard, privacy-conscious clipboard managers like QuietClip store history locally and never transmit pasteboard contents over the network. The clipboard is a shared resource — the manager's job is to keep your data local.
The NSPasteboard API hasn't changed much in decades, and it probably won't. It's a simple, stable foundation — which is exactly what you want from something that runs thousands of times a day on every Mac.
A clipboard manager built on these fundamentals.
QuietClip uses NSPasteboard polling, SwiftData persistence, and zero network code. Your clipboard history stays on your Mac. Free to start, $8.99 once for Pro.