Press a shortcut. Type a few characters. Press Enter.
That's the whole app. This page covers the two capture shortcuts, every key inside the palette, and — the part worth learning — how your query matches and what a copy actually copies.
Capture shortcuts
A capture takes what's on screen, runs on-device OCR, and opens the palette with every recognized line. Two flavors:
| Shortcut (default) | Action |
|---|---|
| ⌥⌘O | Capture the focused window and open the palette. |
| ⌥⌘⇧O | Capture all windows into one merged, searchable list — each line tagged with its source app. |
Both are rebindable: menu-bar icon ▸ Settings… (the same window this guide opens from). Shortcuts must include ⌘, ⌥, or ⌃.
Keys in the palette
| Key | Action |
|---|---|
| type | Filter and re-rank as you type. |
| ↑ / ↓ | Move the selection. |
| ↩ | Copy the selection and dismiss. |
| ⌘↩ | Copy and keep the palette open — grab several things from one capture. |
| ⌘1…⌘9 | Copy the Nth-ranked match and dismiss. |
| esc | Dismiss without copying. |
| click | Select a row; click the selected row again to copy. |
How matching works
Matching is word-confined
A word is anything separated by whitespace. Your query fuzzy-matches inside a single word — the characters you type can be non-contiguous (inv matches Invoice, dcu matches document) — but a match never spans two words: it will not match Is there by borrowing one letter from each.
Spaces mean AND
inv 44 matches lines that have a word matching inv and a word matching 44 — in any order, anywhere on the line.
Ranking
Ranking favors matches at word starts, contiguous runs of your typed characters, and camelCase boundaries. The best match is always on top, so the fastest workflow is: type until the thing you want is #1, then ↩.
What gets copied
The line you see is context; the copy is the payload — shown at full brightness while the rest of the line dims.
total → the bright payload is the word Total; ↩ copies just that. The dim remainder is context.| Query | Copies |
|---|---|
| Empty (browsing) | The whole line. |
| Plain term(s) | Just the matched word(s). total vs Total due: $1,204.00 copies Total. Attached punctuation comes along: 44 vs Invoice #4471 copies #4471. Multiple terms copy each matched word, space-separated. |
.* chunks | The whole span — see below. |
Selecting a span with .*
word1.*word2 selects a chunk: it matches when a word fuzzy-matches word1 and a later word on the same line fuzzy-matches word2, and the copy is everything from the first word through the last, verbatim.
line: npm ERR! Could not resolve dependency query: err.*dep copies: ERR! Could not resolve dependency
Rules of thumb
- It crosses lines. A chunk can start on one line and end on a later one (within the same window; spans never mix windows). The copy keeps the line breaks, and the row shows a
⏎where each break is. Multi-line rows truncate in the middle so you see both ends; linger to expand the whole thing. - Order matters. Like a regex,
.*reads left to right (and top to bottom).dep.*errdoes not match the line above. - Nearest end wins. Each place the first word matches starts a chunk, completed by the nearest following match of the last word. Overlapping chunks ending at the same word collapse to the tightest one.
- The ends are two different words. A chunk needs a first word and a last word, so both terms landing in the same word doesn't count.
- It chains.
from.*via.*toworks — middle terms must match words between the ends, in order. - It composes with spaces.
err.*not npmrequires theerr…notchunk and a word matchingnpmwithin the chunk's lines; both end up in the copy. - While you're still typing.
err.may momentarily match nothing (the dot is literal until the*arrives);err.*behaves like plainerr.
Everyday recipes
| You want | Type |
|---|---|
| An ID, hash, or tracking number | a few of its characters |
| A whole error message | first word .* last word |
| The amount off an invoice | $ or the first digits |
| A URL from a slide | http (or htt.* for the full word) |
| The whole line, but found by keyword | keyword to find it, esc, then arrow to it with an empty query |
That last one is the honest workaround for “I searched to find the line but want all of it” — with a query active, copies take the payload, not the line.
inv, or err.*dep, and press ↩.
Feedback & bug reports
Textracto is a tiny tool made by one person, and real feedback shapes it. Found a bug, hit a window it couldn't read, or wish it did one more thing? Email armand.halbert+textracto@gmail.com — it goes straight to me.
- Bugs: what you captured, what you expected, and what happened. A screenshot of the palette helps.
- Ideas: the thing you wanted to grab and couldn't — those requests drive the roadmap.
- Your setup: your macOS version, so I can reproduce it.