> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/ericclemmons/agent-native/llms.txt
> Use this file to discover all available pages before exploring further.

# Automating Safari

> Navigate web pages and interact with web content in Safari using the Accessibility tree

<Info>
  Safari exposes web content through the Accessibility tree, allowing you to interact with web pages using the same commands as native apps.
</Info>

## Overview

Safari is unique among browsers because it exposes web content as Accessibility nodes. This means you can use agent-native to:

* Navigate to URLs
* Click links and buttons
* Fill forms
* Read page content
* Interact with web applications

<Tip>
  **AX tree peers into browsers** — Safari and Chrome expose web content as AX nodes, making web automation possible without browser-specific APIs.

  See SKILL.md:166 for details.
</Tip>

## Core workflow

<Steps>
  <Step title="Open Safari">
    ```bash theme={null}
    agent-native open Safari
    ```
  </Step>

  <Step title="Navigate to URL">
    Safari's address bar is an `AXTextField`. Find it and fill it:

    ```bash theme={null}
    agent-native snapshot Safari -i | grep -i "address\|search"
    ```

    ```text theme={null}
    AXTextField "Address and Search" [ref=n5]
    ```

    ```bash theme={null}
    agent-native fill @n5 "https://github.com"
    agent-native key Safari return
    sleep 2  # Wait for page load
    ```
  </Step>

  <Step title="Re-snapshot to see page content">
    ```bash theme={null}
    agent-native snapshot Safari -i
    ```

    Web elements appear with their semantic roles: `AXButton`, `AXLink`, `AXTextField`, etc.
  </Step>

  <Step title="Interact with page elements">
    ```bash theme={null}
    # Click a link
    agent-native click @n42

    # Fill a form field
    agent-native fill @n15 "search query"

    # Submit form
    agent-native click @n20
    ```
  </Step>
</Steps>

## Safari's Accessibility tree

Safari represents web pages with semantic HTML roles mapped to AX roles:

| HTML Element              | AX Role         | Notes                    |
| ------------------------- | --------------- | ------------------------ |
| `<button>`                | `AXButton`      | Clickable with `click`   |
| `<a>`                     | `AXLink`        | Clickable with `click`   |
| `<input type="text">`     | `AXTextField`   | Fillable with `fill`     |
| `<input type="checkbox">` | `AXCheckBox`    | Use `check`/`uncheck`    |
| `<input type="radio">`    | `AXRadioButton` | Use `click`              |
| `<select>`                | `AXPopUpButton` | Use `select`             |
| `<h1>` - `<h6>`           | `AXHeading`     | Has level attribute      |
| `<div>`, `<span>`         | `AXGroup`       | Structural containers    |
| `<p>`                     | `AXStaticText`  | Readable with `get text` |

See AXEngine.swift:196-234 for how nodes are built from AX attributes.

## Navigation patterns

### Entering URLs

```bash theme={null}
# Method 1: Fill address bar by ref
agent-native snapshot Safari -i > /tmp/snap.txt
ADDRESS_REF=$(grep -i "Address" /tmp/snap.txt | \
  grep "AXTextField" | grep -o 'ref=n[0-9]*' | sed 's/ref=//' | head -1)

agent-native fill "@$ADDRESS_REF" "https://example.com"
agent-native key Safari return

# Method 2: Use keyboard shortcut
agent-native key Safari cmd+l              # Focus address bar
agent-native key Safari "https://example.com" return

# Method 3: Filter-based (no snapshot needed)
agent-native fill Safari "https://example.com" --label "Address"
agent-native key Safari return
```

<Tip>
  Keyboard shortcuts (`cmd+l`) are fastest for repetitive tasks.
</Tip>

### Navigating back/forward

```bash theme={null}
# Use keyboard shortcuts
agent-native key Safari cmd+[
# Navigate forward
agent-native key Safari cmd+]

# Or click toolbar buttons
agent-native snapshot Safari -i | grep -i "back\|forward"
agent-native click @n3  # Back button
```

### Reloading pages

```bash theme={null}
agent-native key Safari cmd+r
```

### Opening new tabs

```bash theme={null}
agent-native key Safari cmd+t
```

## Form filling

### Text inputs

```bash theme={null}
# Find text fields
agent-native snapshot Safari -i | grep "AXTextField"

# Fill by ref
agent-native fill @n10 "john.doe@example.com"

# Fill by label
agent-native fill Safari "john.doe@example.com" --label "Email"
```

### Checkboxes

```bash theme={null}
# Find checkboxes
agent-native snapshot Safari -i | grep "AXCheckBox"

# Check
agent-native check @n12

# Uncheck
agent-native uncheck @n12

# Check by title
agent-native check Safari --title "I agree to terms"
```

### Dropdowns/Select elements

```bash theme={null}
# Find popup buttons (select elements)
agent-native snapshot Safari -i | grep "AXPopUpButton"

# Select option
agent-native select @n15 "Option A"

# Select by label
agent-native select Safari "United States" --label "Country"
```

See InteractionCommands.swift for the select implementation.

### Radio buttons

```bash theme={null}
# Find radio buttons
agent-native snapshot Safari -i | grep "AXRadioButton"

# Select by clicking
agent-native click @n18

# Click by title
agent-native click Safari --title "Credit Card"
```

### Submit buttons

```bash theme={null}
# Find submit buttons
agent-native snapshot Safari -i | grep -i "submit\|sign in\|login"

# Click
agent-native click @n20

# Or use Enter key
agent-native key Safari return
```

## Example: GitHub login

Complete workflow for logging into GitHub:

```bash theme={null}
#!/usr/bin/env bash
set -euo pipefail

# Open Safari
agent-native open Safari
sleep 1

# Navigate to GitHub login
agent-native key Safari cmd+l
agent-native key Safari "https://github.com/login" return
sleep 3  # Wait for page load

# Snapshot the login page
agent-native snapshot Safari -i > /tmp/github-login.txt

# Find username field
USERNAME_REF=$(grep -i "username\|email" /tmp/github-login.txt | \
  grep "AXTextField" | grep -o 'ref=n[0-9]*' | sed 's/ref=//' | head -1)

if [[ -n "$USERNAME_REF" ]]; then
  agent-native fill "@$USERNAME_REF" "your-username"
  echo "Filled username"
else
  echo "Username field not found"
  exit 1
fi

# Find password field
PASSWORD_REF=$(grep -i "password" /tmp/github-login.txt | \
  grep "AXTextField" | grep -o 'ref=n[0-9]*' | sed 's/ref=//' | head -1)

if [[ -n "$PASSWORD_REF" ]]; then
  agent-native fill "@$PASSWORD_REF" "your-password"
  echo "Filled password"
else
  echo "Password field not found"
  exit 1
fi

# Find and click Sign In button
SIGNIN_REF=$(grep -i "sign in" /tmp/github-login.txt | \
  grep "AXButton" | grep -o 'ref=n[0-9]*' | sed 's/ref=//' | head -1)

if [[ -n "$SIGNIN_REF" ]]; then
  agent-native click "@$SIGNIN_REF"
  echo "Clicked Sign In"
else
  echo "Sign In button not found"
  exit 1
fi

sleep 3  # Wait for login

# Verify login by checking page title
title=$(agent-native get title Safari)
if [[ "$title" == *"GitHub"* ]] && [[ "$title" != *"Login"* ]]; then
  echo "Successfully logged in!"
else
  echo "Login may have failed. Current title: $title"
fi
```

## Example: Searching and clicking links

```bash theme={null}
#!/usr/bin/env bash
set -euo pipefail

# Navigate to Google
agent-native open Safari
agent-native key Safari cmd+l
agent-native key Safari "https://google.com" return
sleep 2

# Find search box
agent-native snapshot Safari -i > /tmp/google.txt
SEARCH_REF=$(grep -i "search" /tmp/google.txt | \
  grep "AXTextField" | grep -o 'ref=n[0-9]*' | sed 's/ref=//' | head -1)

# Perform search
agent-native fill "@$SEARCH_REF" "agent-native macOS"
agent-native key Safari return
sleep 2

# Snapshot search results
agent-native snapshot Safari -i > /tmp/results.txt

# Find and click first result link
FIRST_LINK=$(grep "AXLink" /tmp/results.txt | \
  grep -o 'ref=n[0-9]*' | sed 's/ref=//' | head -1)

if [[ -n "$FIRST_LINK" ]]; then
  agent-native click "@$FIRST_LINK"
  echo "Clicked first result"
fi
```

## Reading page content

### Get text from elements

```bash theme={null}
# Snapshot page
agent-native snapshot Safari -i > /tmp/page.txt

# Read specific element
agent-native get text @n25

# Find headings
grep "AXHeading" /tmp/page.txt

# Extract all text from headings
for ref in $(grep "AXHeading" /tmp/page.txt | grep -o '@n[0-9]*'); do
  agent-native get text "$ref"
done
```

### Get page title

```bash theme={null}
agent-native get title Safari
```

```text theme={null}
GitHub: Let's build from here · GitHub
```

### Check element states

```bash theme={null}
# Check if button is enabled
agent-native is enabled @n10

# Check if checkbox is checked
agent-native get value @n15  # Returns "1" if checked, "0" if unchecked
```

## Working with dynamic content

### Waiting for elements

Use `wait` to wait for elements to appear:

```bash theme={null}
# Wait for a button to appear
agent-native wait Safari --title "Submit" --timeout 5

# Wait for any button
agent-native wait Safari --role AXButton --timeout 10
```

See WaitCommand.swift for implementation.

### Handling page loads

```bash theme={null}
# Navigate
agent-native key Safari cmd+l
agent-native key Safari "https://example.com" return

# Wait for page title to change
old_title=$(agent-native get title Safari)
sleep 2
new_title=$(agent-native get title Safari)

if [[ "$old_title" != "$new_title" ]]; then
  echo "Page loaded: $new_title"
fi

# Or use fixed delay
sleep 3  # Wait 3 seconds for page load
```

### Re-snapshotting after interactions

```bash theme={null}
# Click a button that loads new content
agent-native click @n10
sleep 1

# Re-snapshot to see new content
agent-native snapshot Safari -i > /tmp/updated.txt
```

## Common Safari keyboard shortcuts

| Shortcut    | Action            |
| ----------- | ----------------- |
| `cmd+l`     | Focus address bar |
| `cmd+t`     | New tab           |
| `cmd+w`     | Close tab         |
| `cmd+r`     | Reload page       |
| `cmd+[`     | Back              |
| `cmd+]`     | Forward           |
| `cmd+f`     | Find in page      |
| `cmd+plus`  | Zoom in           |
| `cmd+minus` | Zoom out          |
| `cmd+0`     | Reset zoom        |

## Best practices

<CardGroup cols={2}>
  <Card title="Wait for page loads" icon="hourglass">
    Always add delays after navigation:

    ```bash theme={null}
    agent-native key Safari return
    sleep 3  # Wait for page load
    ```
  </Card>

  <Card title="Use keyboard shortcuts" icon="keyboard">
    Shortcuts are more reliable than clicking toolbar buttons:

    ```bash theme={null}
    agent-native key Safari cmd+l  # Focus address bar
    agent-native key Safari cmd+r  # Reload
    ```
  </Card>

  <Card title="Check page titles" icon="window">
    Verify navigation by checking titles:

    ```bash theme={null}
    title=$(agent-native get title Safari)
    echo "Current page: $title"
    ```
  </Card>

  <Card title="Handle dynamic content" icon="rotate">
    Use `wait` for elements that load asynchronously:

    ```bash theme={null}
    agent-native wait Safari --title "Submit" --timeout 5
    ```
  </Card>
</CardGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Web elements not appearing in snapshot">
    **Possible causes:**

    * Page not fully loaded
    * Content is in an iframe
    * Elements are dynamically rendered

    **Solutions:**

    1. Wait longer for page load:
       ```bash theme={null}
       sleep 5
       agent-native snapshot Safari -i
       ```
    2. Check full tree without `-i` flag:
       ```bash theme={null}
       agent-native snapshot Safari > full-tree.txt
       ```
    3. Try increasing depth:
       ```bash theme={null}
       agent-native snapshot Safari -i -d 15
       ```
  </Accordion>

  <Accordion title="Address bar not found">
    **Solutions:**

    1. Use keyboard shortcut instead:
       ```bash theme={null}
       agent-native key Safari cmd+l
       agent-native key Safari "https://example.com" return
       ```
    2. Search for "Address" or "Search":
       ```bash theme={null}
       agent-native find Safari --title "Address"
       ```
  </Accordion>

  <Accordion title="Form submission not working">
    **Possible causes:**

    * Submit button requires specific event
    * Form validation failing

    **Solutions:**

    1. Try pressing Enter instead of clicking:
       ```bash theme={null}
       agent-native key Safari return
       ```
    2. Check if validation errors appear:
       ```bash theme={null}
       agent-native snapshot Safari -i | grep -i "error\|invalid"
       ```
    3. Verify all required fields are filled
  </Accordion>

  <Accordion title="Clicking wrong element">
    **Problem:** Multiple elements with similar titles.

    **Solutions:**

    1. Use more specific filters:
       ```bash theme={null}
       agent-native click Safari --title "Submit" --role AXButton
       ```
    2. Use index to select specific match:
       ```bash theme={null}
       # Uses filter-based resolution with index
       # (Not exposed in CLI but available in ElementResolver.swift:13)
       ```
    3. Inspect elements to verify:
       ```bash theme={null}
       agent-native find Safari --title "Submit"
       agent-native inspect @n10
       ```
  </Accordion>

  <Accordion title="Page content not updating">
    **Problem:** Snapshot shows old content after interaction.

    **Cause:** Need to wait for page update.

    **Solutions:**

    1. Add delay before re-snapshotting:
       ```bash theme={null}
       agent-native click @n10
       sleep 2
       agent-native snapshot Safari -i
       ```
    2. Use `wait` for specific element:
       ```bash theme={null}
       agent-native wait Safari --title "Success" --timeout 5
       ```
  </Accordion>
</AccordionGroup>

## Limitations

<Warning>
  **Safari AX limitations:**

  * Some JavaScript-heavy SPAs may have incomplete AX trees
  * Canvas-based content (games, visual editors) is not accessible
  * Shadow DOM elements may be hidden
  * Some modern frameworks render minimal semantic HTML
</Warning>

For complex web automation, consider:

* Using simpler, more accessible websites
* Combining with screenshots for visual verification
* Using keyboard shortcuts when AX tree is sparse
* Testing with Safari's Accessibility Inspector first

## Next steps

<CardGroup cols={2}>
  <Card title="Electron apps" icon="atom" href="/guides/electron-apps">
    Automate Slack, Discord, and VS Code
  </Card>

  <Card title="System Settings" icon="gear" href="/guides/system-settings">
    Configure macOS system settings
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/guides/troubleshooting">
    Fix common issues and errors
  </Card>

  <Card title="API reference" icon="code" href="/reference/command-list">
    Explore all commands
  </Card>
</CardGroup>
