Module for interacting with the macOS pasteboard (clipboard)
The macOS pasteboard is "rich" — a single clipboard operation can carry multiple representations
of the same content for different applications to consume. For example, text copied from a web
browser may carry plain text, HTML, and RTF representations simultaneously.
Basic Usage
// Read and write plain text
const text = hs.pasteboard.readString()
hs.pasteboard.writeString("Hello from Hammerspoon!")
// Check what types are currently on the pasteboard
const available = hs.pasteboard.types()
// Write multiple representations at once
hs.pasteboard.writeObjects({
"public.utf8-plain-text": "Hello",
"public.html": "<b>Hello</b>"
})
// Watch for pasteboard changes
const handler = (changeCount) => {
console.log("Pasteboard changed, count:", changeCount)
console.log("New text:", hs.pasteboard.readString())
}
hs.pasteboard.addWatcher(handler)
// Later: hs.pasteboard.removeWatcher(handler)
Pasteboard Conventions (nspasteboard.org)
macOS has no built-in notification API for transient or confidential clipboard content, so a
community convention has emerged (see nspasteboard.org) around four
org.nspasteboard.* UTI marker types. These markers carry no payload — their mere presence on
the pasteboard signals intent to other applications.
Standard marker UTIs
UTI
Meaning
org.nspasteboard.TransientType
Content is temporary; it will be removed or overwritten shortly. Clipboard historians should not record this change.
org.nspasteboard.ConcealedType
Content is sensitive (e.g. a password). Historians should obfuscate it if displayed and ideally encrypt it if stored.
org.nspasteboard.AutoGeneratedType
Content was placed by an application without any user Copy action. Historians should generally skip recording it.
org.nspasteboard.source
The bundle identifier of the application that placed the content. Use an empty string when the source is unknown.
Legacy proprietary markers
Several apps defined their own markers before the org.nspasteboard.* standard existed.
Clipboard historians should also honour these for compatibility:
UTI
Application
de.petermaurer.TransientPasteboardType
TextExpander, Butler
com.typeit4me.clipping
TypeIt4Me
Pasteboard generator type
Typinator
com.agilebits.onepassword
1Password (confidential)
com.apple.is-remote-clipboard
macOS (remote content)
For scripts that write to the pasteboard
If your script temporarily commandeers the pasteboard (e.g. to trigger a paste), add
org.nspasteboard.TransientType so clipboard historians skip the entry:
The pasteboard change count. Increments each time any application writes to the pasteboard.
Comparing a saved value to the current value is the standard way to detect external changes.
The polling interval for the pasteboard watcher, in seconds. Defaults to 0.5.
Changes take effect the next time a watcher is started (i.e. after removing and re-adding).
Write raw base64-encoded data for a specific UTI type, replacing all current contents.
Use this for types not covered by the convenience write methods.
Write multiple type representations to the pasteboard atomically, replacing all current contents.
Keys must be UTI type strings; values must be strings. This is how you provide both a plain-text
fallback and a richer representation (such as HTML) in a single clipboard operation.
Add a watcher that is called whenever the pasteboard contents change.
Multiple watchers may be registered; they are each called independently.
Because macOS provides no pasteboard change notification API, this is implemented
by polling `changeCount` at the interval specified by `watcherInterval`.
Declaration
hs.pasteboard.addWatcher(listener) -> None
Parameters
Name
Type
Description
listener
JSValue
A function called with one argument: the new `changeCount` integer