Where does the copy operation go?
The page sees a method called clipboard.write. Its
implementation in the preload is a wrapper. The useful question is
what that wrapper sends, and which code receives it.
Use REA to trace how Notion copies text and HTML to the system clipboard. Show the code at each step.
An example prompt with Notion's local application package available to your coding agent.
REA finds where to start reading
Analyzing the tab preload with REA locates the API exposed to the page and the call that sends an IPC request. Both findings come with source ranges in the minified bundle:
REA findings → two places to open
api_key: "__electronApi"
api_status: "dynamic"
source: preload.js:1:22764–22828
operation: "invoke"
channel_expression: "e"
source: preload.js:1:6486–6522
analyze_javascript_application result on Notion's
tab preload, recorded with REA 4.1.0. Positions use the original
bundle's line and zero-based column.
The agent opens those locations, finds the clipboard member in the
assembled API, and reads invokerInMain. Its call site
supplies
notion:clipboard:write. That
name gives the agent something precise to look for in the main
bundle. The four excerpts below show the route it connects.
Four short pieces of code
Simplified from the packaged JavaScript, with readable variable names. Unrelated members are omitted.
-
Start at the API exposed to the page
tab_browser_view/preload.js · API memberconst clipboardApi = { write: invokerInMain("notion:clipboard:write") }; // Included in the API exposed through contextBridge: // window.__electronApi.clipboardThis member supplies the channel name. The implementation of
invokerInMaintells us how the request leaves the page's process. -
Resolve the preload's wrapper
tab_browser_view/preload.js · IPC helperfunction invokerInMain(channel) { return (...args) => invokeInMainAndReturnResult(channel, ...args); } function invokeInMainAndReturnResult(channel, ...args) { return ipcRenderer.invoke(channel, ...args); }The returned function forwards the arguments through Electron's request-and-response IPC. We can now look for
notion:clipboard:writeon the main-process side. -
Check how the receiver is registered
main/index.js · handler helperconst handleRequestFromRenderer = { addListener(channel, handler) { ipcMain.handle(channel, handler); } };The main process uses another wrapper. Its
addListenermethod registers anipcMain.handlereceiver for that channel. -
Find the write and its sender check
main/index.js · clipboard receiverhandleRequestFromRenderer.addListener( "notion:clipboard:write", (event, data) => isNotionWebContents(event.sender) ? clipboard.write(data) : undefined );This is the destination. After checking the sender, the handler passes the supplied data to Electron's clipboard API. The channel and the two resolved wrappers connect the exposed method to this call.
How does a copied block keep its structure?
Notion's web editor sends text and HTML through
electronApi.clipboard.write. It keeps the block data
locally and puts an ID in the copied HTML to connect them.
HTML links to saved block data
text: "Project notes"
html: "<p>Project notes</p>"
+ "<!-- notionvc: <copy-id> -->"
id: <copy-id>
mimeTypes:
text/_notion-blocks-v3-production
→ structured block data
- Read the HTML ID
- Find the same local ID
- Restore Notion block data
On paste, Notion looks for the HTML ID and checks it against the saved copy. Matching IDs restore the block data.
Clipboard format recorded from web assets cached on July 13, 2026.
More examples and sources
Another example: Markdown tables
Notion parses Markdown into block data. This example shows how a table becomes header and data rows.
A table through Notion's Markdown parser
| A | B |
| - | - |
| 1 | 2 |
table · headerRow: true
table_row
cells: ["A"], ["B"]
table_row
cells: ["1"], ["2"]
Another path: the offline SQLite connection
Notion's renderer requests getSqliteMeta through
IPC. The main process creates a message channel and gives one
port to the renderer and the other to a SQLite utility process.
Subsequent statement batches and results travel over that port.
Following this handoff explains where the database work runs, and why tracing only the initial IPC request misses the later conversation.
Sources and how to read the excerpts
The clipboard bridge comes from Notion Desktop 7.6.1's
app.asar: the tab preload and
main/index.js. The excerpts expand minified
variable names and omit unrelated code; the sender-check helper
is shown with its underlying
isNotionWebContents call.
The virtual clipboard and Markdown examples come from web assets
cached on July 13, 2026, including modules 747001,
58169, 736810 and 422457.
Those assets have their own version. Saved probes executed
extracted modules and small harnesses; their outputs describe
those probes rather than a captured desktop UI session.
The REA result shown here is a focused analysis of the saved tab preload, recorded with the published REA 4.1.0 package. It locates the API and invoke operation. The clipboard member and matching receiver are connected by reading their wrapper implementations in the package.
The Markdown example uses parser module 422457.
Saved module tests show that both page and chat filters preserve
this table. The paste/import, structured Markdown and AI/chat
parsers have separate entry points and intermediate formats.
- JavaScript application guideFollow a small Electron application's export feature.
- DX-Ball reconstructionFollow native instructions to a checked C function.