Using AppleScript to detect if a Safari window uses Private Browsing

Last year, I wrote an AppleScript function that opens a URL in a Private Browsing window in Safari. I got an email from a reader asking if I knew how to open a URL in a Private Browsing tab – either adding it to an existing private window, or creating a new private window if not.

The difficult part is working out if a given window is using Private Browsing. Although you can access Safari’s windows and tabs using AppleScript, it doesn’t tell you whether a window is private. We need to work it out on our own.

This used to be possible by using the do JavaScript action to run code within the webpage. You couldn’t use localStorage.setItem in private mode, so if it was unavailable you’d know you were in private browsing. Unfortunately, browser vendors don’t want web pages to be able to detect of they’re in private browsing, and they tend to patch JavaScript-based detection. I’m not aware of a good way to detect private browsing using JavaScript in Safari 14.

That said, we’re not confined to the web page. We’re running AppleScript on our Mac, so we have access to everything in the browser. Windows, menus, web pages, the lot.

Is there some other clue that would tell us if we’re in private browsing?

Poking around a bit, I discovered something interesting in the Window menu: the menu item to move a tab to a new window changes depending on whether you’re in private browsing or not.

A menu with an item 'Move Tab to New Window' highlighted in red. A menu with an item 'Move Tab to New Private Window' highlighted in red.

This gives us a way in – we can use System Events to inspect the items in the Window menu, and the label on this item will tell us if the frontmost window is private. It works even if there’s a single tab (or no tab) in the window – the menu item will be present, just inactive.

Here’s what the code looks like:

on isFrontmostSafariWindowPrivateBrowsing()
  -- If you don't activate Safari, the results are sometimes wrong.
  -- In particular, System Events doesn't have the most up-to-date
  -- information about the state of the menu.
  --
  -- I think this is the same problem as described in
  -- https://www.reddit.com/r/applescript/comments/an1cpj/information_in_system_events_not_updating/
  tell application "Safari" to activate

  tell application "System Events"
    set theWindowMenu to menu "Window" of ¬
      menu bar 1 of ¬
      application process "Safari"

    return (menu item "Move Tab to New Private Window" of theWindowMenu) exists
  end tell
end isFrontmostSafariWindowPrivateBrowsing

As I explained at the end of my previous post, you’ll need to give Accessibility permissions to whatever app uses this code. Apps can’t just inspect the menu items of other processes – that would open up all sorts of weird security holes.

This code has a couple of limitations:

In an ideal world, Apple would add this property to a future version of the Safari AppleScript Scripting Dictionary. In reality, they’ve given it very little attention in the last few years, and they’re just as likely to remove it as improve it. For now, this code works, and proves you can still make lots of useful things in AppleScript.