Read the rows of an app's list
Reads the rows of a table, outline or list in any app (Mail's inbox, a Finder list, Numbers, Activity Monitor) as named, typed fields.
Read the rows of locator into into
Details #
Reads the table, outline or list you name with locator, or, with none, the biggest one in the front window of app (the front app by default). Every row becomes a dictionary: {from: "Ada", subject: "Lunch?", date: "2026-10-26"}. The result is {rows, count, headers, truncated, pages, container, source: {app, window, at}}, and {{ res.rows }} is a list for Repeat, Save rows to a file or the clipboard and return. The step's note says which one it chose (AXTable "Message list" · 412 rows).
Columns. A table or outline names its columns from its header (Date Modified becomes dateModified); a list with no header gets c0, c1, and so on. When every value in a column reads as a date, or as a plain number, the column is typed that way; a column with anything else stays text. as changes that: as: "text" turns the guessing off, as: {"size": "number"} types one column by its name.
Fields. fields shapes the columns yourself: {name: {at, what, regex, as, all, default}}, each relative to the row. at is the position of the piece in the row (0 is the first; a cell that holds several texts, like a Mail row, counts each text), an element role (AXLink) or an element's title. what is value, title, description, url, exists or count; without it the first one the element has is used. regex keeps its first capture group. all gives a list for a field that repeats inside a row. as is text, number (currency signs, thousands separators, 1.2k), date (ISO, Oct 25, 2 hours ago), url, boolean or list, the same as Scrape a page into rows. A value that won't convert is null, and the note says which row and why.
Key and limit. key names the column that identifies a row, so a row seen twice is dropped. limit stops after that many rows (2000 by default); the result then says truncated.
Lists that only hold what is on screen. Some lists (SwiftUI lazy lists, web tables) only have the visible rows in the accessibility tree. When that looks like the case the result says truncated with the reason. scroll: true reads the page, scrolls to the last row, reads again and so on until nothing new appears (at most 20 seconds), then puts the scroll position back. The window moves while that runs, so don't use the Mac meanwhile.
Disclosed outline rows keep their nesting as level (0 at the top). Reading is silent: no HUD, and nothing in the app changes.
Parameters #
| Parameter | Type | Required | Values | What it does |
|---|---|---|---|---|
app | text | The app to look in, by bundle id. Defaults to the locator's app, otherwise the front app. | ||
as | any value | |||
fields | record | , as, key, limit, scroll: As above. | ||
fuzzy | yes / no | Accept a 40% to 70% locator match, with a warning. | ||
into | text | The variable that receives the result. | ||
key | text | |||
limit | number | |||
locator | locator | The table, outline or list. Optional. | ||
sample | any value | |||
scroll | yes / no |
Every step also accepts label, onFailure, timeout and dryRunSafe.
Examples #
- Read the rows of the list in Mail into res
- Save rows to “Inbox.csv”
Gotchas #
A dry run skips this step unless you mark it Safe in dry run. It only reads, so that is safe to do.
It needs the Accessibility permission, and it reads only what the app tells Accessibility. A password manager's list gives titles and addresses only if the app offers them.
An app that describes nothing (a game, a canvas, Electron before accessibility is on) has no rows to read. The step says so; Switchboard turns accessibility on for Chromium and Electron apps by itself.
Where the same row can be on screen twice (a long list read with
scroll), give it akey, or the second copy of a row that looks the same is dropped.
See also #
Save rows to a file or the clipboard, Read all the text of an app's document, Read field value, Scrape a page into rows, An element in an app changes