Integrating with non-Electron apps
Use a small Node.js sidecar process to use the DSDK with Tauri, Swift, and other native apps.
The Desktop Recording SDK is distributed as an npm package. When using Electron apps, it is straightforward to use it directly. In apps built on other frameworks (e.g. Tauri), you can still use the SDK by running it inside a small Node.js sidecar process that your app spawns and communicates with over standard I/O.
How the sidecar works
Your app spawns a Node.js process you ship inside it. That process loads @recallai/desktop-sdk, which in turn spawns the Recall native binary. Your app and the sidecar talk to each other over stdin/stdout.
Keep the sidecar small. It should expose the SDK's methods over some kind of IPC protocol (typically line-delimited JSON over stdio) and forward SDK events back to your app. All UI, state, and business logic can stay in your main app.
MacOS: Don't bundle Homebrew'snodeHomebrew's
nodeon macOS is dynamically linked againstlibnode.dyliband other dylibs in/opt/homebrew/Cellar/. It will not run when copied into your app bundle on its own. Use the official self-contained binary from nodejs.org instead.
Tauri
Tauri has first-party documentation for embedding a Node.js sidecar in a Tauri v2 app. You can find that here.
The Tauri guide assumes a self-contained Node script. The SDK locates its native binary and Frameworks/ directory at runtime relative to its own JS file, so the guide's pkg / bun build --compile path won't work as-is — you'll need to make sure the SDK's node_modules/@recallai/desktop-sdk/ directory ends up in your packaged app. One workable approach is to ship an official Node binary via bundle.externalBin and put your sidecar script plus node_modules under Tauri's resources, but the specific layout is up to you.
A few smaller things specific to a Tauri integration:
- The sidecar is long-lived. Tauri's guide example calls
.output()for a one-shot command. For an ongoing bidirectional sidecar, use.spawn()instead — it returns a(Receiver<CommandEvent>, CommandChild)tuple. Hold onto theCommandChildfor the lifetime of the sidecar; if you drop it, the child process is killed. - Tauri's
setup()hook is synchronous and has no live Tokio reactor. If you spawn the sidecar fromsetup(), wrap the spawn intauri::async_runtime::block_on(...)and usetauri::async_runtime::spawn(nottokio::spawn) for background tasks.
Swift / Native macOS
There's no first-party guide for embedding a Node.js sidecar in a Swift app, but Foundation's Process and Pipe cover everything you need. The rough shape:
- Put a Node binary, your sidecar script, and
node_modules(with the SDK intact) intoYourApp.app/Contents/Resources/. - Spawn
ProcesswithexecutableURLpointing at the bundled Node andargumentspointing at the sidecar script. - Wire up three
Pipes forstdin,stdout, andstderr. - Write IPC requests to
stdin; read events and responses fromstdout.
A few smaller things specific to a Swift integration:
Pipe.fileHandleForReading.readabilityHandlerdelivers raw byte chunks, not lines. If your IPC is line-based, you'll need to buffer and split on\nyourself.- You don't need an Xcode project. Swift Package Manager produces an executable you can assemble into a
.appbundle by hand.
Other frameworks
The same pattern works for any framework that can spawn a child process and read and write its standard I/O. The specifics will differ — how you spawn, how you read stdout, how you bundle Node — but the architecture is the same. If you're integrating from a framework not covered here and run into trouble, reach out to support.
Updated about 11 hours ago