← Back to DevBytes

macOS AppleScript Automation

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:

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.

— Ad —

Google AdSense will appear here after approval

← Back to all articles