Extract Safari Titles and URLs via AppleScript and JXA

This article explains how to automate the extraction of webpage titles and URLs from all open windows and tabs in the Safari web browser on macOS. It provides ready-to-use scripts and clear explanations for both AppleScript and JavaScript for Automation (JXA), demonstrating how to iterate through browser elements to retrieve their data efficiently.

Using AppleScript

To extract data from Safari using AppleScript, you must communicate with the application's scripting dictionary. Safari organizes its elements hierarchically: the application contains windows, and each window contains tabs. Each tab has a name property (the title) and a URL property.

Here is the AppleScript to iterate through every window and tab:

set extractedData to ""

tell application "Safari"
    set windowList to every window
    repeat with aWindow in windowList
        -- Ensure the window actually supports tabs (ignores preference panes)
        if exists tabs of aWindow then
            set tabList to every tab of aWindow
            repeat with aTab in tabList
                set tabTitle to name of aTab
                set tabURL to URL of aTab
                set extractedData to extractedData & tabTitle & " | " & tabURL & linefeed
            end repeat
        end if
    end repeat
end tell

return extractedData

How the AppleScript Works

  1. tell application "Safari": Directs the script's commands to the Safari browser.
  2. repeat with aWindow in windowList: Starts the outer loop, iterating through all open Safari windows.
  3. if exists tabs of aWindow: Prevents errors by ensuring the current window is a standard browser window and not a dialog box or settings window.
  4. repeat with aTab in tabList: Starts the inner loop, going through each tab inside the current window.
  5. name of aTab and URL of aTab: Extracts the title and web address, appending them to the extractedData text variable, separated by a line break.

Using JavaScript for Automation (JXA)

JavaScript for Automation (JXA) provides an alternative way to interact with macOS applications using standard JavaScript syntax. In JXA, properties are accessed as methods (using parentheses) rather than simple values.

Here is the JXA script to achieve the same result:

const safari = Application("Safari");
let extractedData = [];

const windows = safari.windows();

for (let i = 0; i < windows.length; i++) {
    const currentWindow = windows[i];
    
    // Check if the window has valid tabs
    let tabs;
    try {
        tabs = currentWindow.tabs();
    } catch (e) {
        continue; 
    }

    for (let j = 0; j < tabs.length; j++) {
        const currentTab = tabs[j];
        const tabTitle = currentTab.name();
        const tabURL = currentTab.url();
        
        extractedData.push(`${tabTitle} | ${tabURL}`);
    }
}

extractedData.join("\n");

How the JXA Script Works

  1. Application("Safari"): Instantiates the Safari application object.
  2. safari.windows(): Calls the windows method to return an array of open window objects.
  3. try...catch block: Safely attempts to get the tabs() array for the current window. If a non-browser window is encountered, it skips to the next iteration.
  4. currentTab.name() and currentTab.url(): Calls the methods on the tab object to retrieve the title and URL strings.
  5. extractedData.join("\n"): Combines all elements of the array into a single string separated by new lines and returns the final output.

How to Run the Scripts

You can execute both of these scripts natively on macOS using two methods:

Method 1: Script Editor

  1. Open the Script Editor application (located in /Applications/Utilities/).
  2. Click New Document.
  3. Set the language dropdown in the top-left corner (below the record buttons) to either AppleScript or JavaScript.
  4. Paste the corresponding code into the editor.
  5. Click the Play (Run) button in the toolbar. The extracted titles and URLs will appear in the Result pane at the bottom of the window.

Method 2: Terminal (Command Line)

You can run these scripts directly from the macOS Terminal using the osascript command.

To run the AppleScript file from the terminal:

osascript path/to/script.scpt

To run the JXA file from the terminal, you must include the -l JavaScript flag:

osascript -l JavaScript path/to/script.js