Browse the docs

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 #

ParameterTypeRequiredValuesWhat it does
apptextThe app to look in, by bundle id. Defaults to the locator's app, otherwise the front app.
asany value
fieldsrecord, as, key, limit, scroll: As above.
fuzzyyes / noAccept a 40% to 70% locator match, with a warning.
intotextThe variable that receives the result.
keytext
limitnumber
locatorlocatorThe table, outline or list. Optional.
sampleany value
scrollyes / no

Every step also accepts label, onFailure, timeout and dryRunSafe.

Examples #

Mail's inbox to a CSV on the desktop
Do
  1. Read the rows of the list in Mail into res
  2. Save rows to “Inbox.csv”
Open in Switchboard to try it

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 a key, 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