Introduction to macOS AppleScript Automation
AppleScript is a scripting language built into macOS that allows developers and power users to automate tasks by communicating with applications and the operating system. Unlike general-purpose scripting languages, AppleScript is designed specifically to control Mac applications through a human-readable, English-like syntax. This makes it one of the most accessible automation tools available on the platform, while still being powerful enough for complex workflows.
For developers, AppleScript offers a way to bridge applications that might not otherwise communicate. You can automate file operations, control creative tools like Photoshop or Logic Pro, manipulate the Finder, send messages through Mail, and even chain multiple applications together in a single workflow. When combined with shell scripts, Shortcuts, and tools like osascript, AppleScript becomes a versatile piece of any macOS automation toolkit.
Why AppleScript Matters for Developers
While modern macOS offers several automation options — including Shortcuts, JavaScript for Automation (JXA), and shell scripting — AppleScript remains relevant for several reasons:
- Deep application integration: Many Mac apps expose rich AppleScript dictionaries that are not available through any other interface.
- Human-readable syntax: Scripts are easy to read, review, and maintain, even by team members who are not automation specialists.
- Native support: No additional runtime or package manager is required. AppleScript runs out of the box on every Mac.
- Interoperability: AppleScript can invoke shell commands, call Objective-C bridges, and be embedded in Swift apps.
- Stability: AppleScript has been part of macOS for decades, and its core APIs are remarkably stable.
For developers building internal tools, release pipelines, or productivity utilities, AppleScript can eliminate repetitive manual steps that would otherwise consume hours each week.
Getting Started with AppleScript
The Script Editor
macOS includes a built-in application called Script Editor (located in /System/Applications/Utilities/). This is the primary environment for writing, testing, and debugging AppleScript. It provides syntax highlighting, a results panel, and access to application dictionaries.
To open an application's dictionary, launch Script Editor, go to File > Open Dictionary, and select the application you want to inspect. The dictionary describes the commands, objects, and properties that the application exposes to AppleScript.
Running Scripts from the Command Line
AppleScript can also be executed from the terminal using the osascript command. This is essential for integrating AppleScript into shell scripts, cron jobs, and CI pipelines.
# Display a simple dialog from the terminal
osascript -e 'display dialog "Hello from the terminal!"'
You can also pass a file containing an AppleScript:
osascript ~/scripts/my_automation.scpt
Basic Syntax and Concepts
Variables and Data Types
Variables in AppleScript are declared with the set keyword. The language supports strings, integers, real numbers, lists, records, and booleans.
set userName to "Alice"
set itemCount to 42
set price to 19.99
set isActive to true
set tags to {"dev", "mac", "automation"}
set userRecord to {name:"Alice", role:"Engineer"}
-- Display the values
display dialog "User: " & userName & " with " & (itemCount as string) & " items"
Control Flow
AppleScript supports standard control flow constructs including if statements, repeat loops, and try blocks for error handling.
set temperature to 75
if temperature > 80 then
display dialog "It's hot outside."
else if temperature > 60 then
display dialog "The weather is pleasant."
else
display dialog "It's cold. Bring a jacket."
end if
-- Loop through a list
set fruits to {"apple", "banana", "cherry"}
repeat with fruit in fruits
log fruit
end repeat
-- Error handling
try
set fileRef to open for access file "Macintosh HD:nonexistent.txt"
on error errMsg
display dialog "Error: " & errMsg
end try
Handlers (Functions)
Reusable logic is organized into handlers. Handlers can accept parameters and return values.
on greet(name, greeting)
return greeting & ", " & name & "!"
end greet
set message to greet("Alice", "Welcome")
display dialog message
Automating the Finder
One of the most common uses of AppleScript is automating file operations through the Finder. The following script creates a new folder on the Desktop and moves all PNG files into it.
tell application "Finder"
set desktopFolder to folder "Desktop" of home
set newFolder to make new folder at desktopFolder with properties {name:"Screenshots"}
set imageFiles to every file of desktopFolder whose name extension is "png"
repeat with img in imageFiles
move img to newFolder
end repeat
display dialog "Moved " & (count of imageFiles) & " files."
end tell
The tell block directs subsequent commands to a specific application. This is the fundamental mechanism for controlling apps with AppleScript.
Controlling Other Applications
Automating Safari
Safari exposes a useful AppleScript dictionary for opening URLs, executing JavaScript, and retrieving page content.
tell application "Safari"
activate
set newDoc to make new document with properties {URL:"https://developer.apple.com"}
-- Wait for the page to load
delay 3
-- Execute JavaScript and retrieve the page title
set pageTitle to do JavaScript "document.title" in newDoc
display dialog "Page title: " & pageTitle
end tell
Sending Email with Mail
You can compose and send emails programmatically through the Mail application.
tell application "Mail"
set newMessage to make new outgoing message with properties {subject:"Build Complete", content:"The latest build finished successfully."}
tell newMessage
make new to recipient at end of to recipients with properties {address:"team@example.com"}
set visible to true
end tell
send newMessage
end tell
Working with Calendar
AppleScript can create events and reminders in the Calendar app, which is useful for automated scheduling.
tell application "Calendar"
tell calendar "Work"
make new event with properties {summary:"Code Review", start date:(current date) + 3600, end date:(current date) + 7200}
end tell
end tell
Integrating AppleScript with Shell Scripts
AppleScript and shell scripting complement each other well. You can call shell commands from within AppleScript using do shell script, and you can call AppleScript from the shell using osascript.
-- Run a shell command and capture the output
set fileList to do shell script "ls -la ~/Downloads"
display dialog fileList
A practical example: a shell script that uses AppleScript to display a native macOS notification when a long-running task completes.
#!/bin/bash
# build_and_notify.sh
# Simulate a long build process
echo "Building project..."
sleep 5
echo "Build complete."
# Send a native notification via AppleScript
osascript -e 'display notification "Build finished successfully" with title "CI Pipeline" sound name "Glass"'
Embedding AppleScript in Swift Applications
If you are building a native macOS app, you can execute AppleScript directly from Swift using NSAppleScript. This is useful for adding automation features to your own applications.
import Foundation
let script = """
tell application "Finder"
empty trash
end tell
"""
var error: NSDictionary?
if let appleScript = NSAppleScript(source: script) {
let output = appleScript.executeAndReturnError(&error)
if let error = error {
print("AppleScript error: \(error)")
} else {
print("Script output: \(output.stringValue ?? "")")
}
}
Note that executing AppleScript from a sandboxed app requires appropriate entitlements and may prompt the user for permission. Always test automation features in the context of your app's sandbox configuration.
Best Practices
1. Always Use Try Blocks for External Dependencies
Applications may not be running, files may not exist, and permissions may be denied. Wrap external interactions in try blocks to handle failures gracefully.
try
tell application "Safari"
if (count of documents) > 0 then
set currentURL to URL of document 1
end if
end tell
on error errMsg number errNum
log "Failed to read Safari URL: " & errMsg & " (" & errNum & ")"
end try
2. Avoid Hardcoded Delays When Possible
While delay is sometimes necessary, relying on fixed waits makes scripts fragile. Instead, poll for a condition or use application-specific events when available.
-- Instead of a fixed delay, poll for the page to finish loading
tell application "Safari"
repeat 30 times
if (do JavaScript "document.readyState" in document 1) is "complete" then exit repeat
delay 0.5
end repeat
end tell
3. Read Application Dictionaries
Before writing automation for an application, always consult its dictionary. The dictionary reveals the exact object model, available commands, and property names. Guessing property names leads to runtime errors that are difficult to debug.
4. Keep Scripts Modular
Break large scripts into handlers and save reusable handlers in script libraries. macOS supports loading script objects from external files, which promotes code reuse across projects.
-- Save this as ~/Library/Script Libraries/FileUtils.scpt
on moveFilesByExtension(sourceFolder, destFolder, ext)
tell application "Finder"
set matchedFiles to every file of folder sourceFolder whose name extension is ext
repeat with f in matchedFiles
move f to folder destFolder
end repeat
return (count of matchedFiles)
end tell
end moveFilesByExtension
-- Load and use the library
set FileUtils to script "FileUtils"
set movedCount to FileUtils's moveFilesByExtension("Macintosh HD:Users:you:Downloads", "Macintosh HD:Users:you:Pictures", "jpg")
5. Log for Debugging
Use the log command to write diagnostic output to the Script Editor's messages pane or to the system log when running via osascript. This is invaluable for troubleshooting complex workflows.
6. Respect User Permissions
Modern macOS requires explicit user permission for automation. When your script controls another application for the first time, the user will see a permission prompt. Design your scripts and applications to handle denied permissions gracefully, and provide clear messaging about why automation access is needed.
Conclusion
AppleScript remains a uniquely powerful tool for macOS automation, offering direct access to application features that no other scripting language can match. By understanding its syntax, leveraging application dictionaries, and following best practices around error handling and modularity, developers can build robust automation workflows that save time and reduce manual effort. Whether you are organizing files, orchestrating multi-app pipelines, or embedding automation into a native Swift application, AppleScript provides a reliable bridge between the applications on your Mac and the workflows you want to automate.