# How Meetily Handles Real-Time Communication: Tauri Events and React Listeners

> Discover how Meetily uses Tauri events and React listeners for real-time communication. Learn how this Rust and Nextjs app achieves bidirectional communication without a separate network server.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: internals
- Published: 2026-07-29

---

**Meetily leverages Tauri's built-in event system to enable bidirectional real-time communication between its Rust backend and Next.js frontend, eliminating the need for a separate network server.**

Meetily is an open-source meeting assistant built by Zackriya-Solutions that combines a Rust-powered audio pipeline with a modern Next.js interface. Understanding how Meetily handles real-time communication reveals a sophisticated event-driven architecture that streams live transcripts and recording states without network latency. This article examines the specific implementation details found in the Meetily source code, from Rust event emissions to React context listeners.

## Backend-to-Frontend Event Emission in Rust

The Rust backend drives real-time updates through Tauri's `emit` method. When critical audio events occur, the application state manager broadcasts payloads to all subscribed frontend listeners.

### Recording State Events

In [`frontend/src-tauri/src/audio/recording_commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/recording_commands.rs), the backend signals recording lifecycle changes immediately after state transitions. When a user initiates capture, the system emits a structured payload containing meeting metadata at lines 294-298.

```rust
// In recording_commands.rs – after a recording is started
let _ = app.emit(
    "recording-started",
    serde_json::json!({ "meeting_name": meeting_name })
);

```

### Transcript Streaming Events

As the Whisper transcription pipeline processes audio chunks, each result triggers a `transcript-update` event. The code at lines 902-910 of [`recording_commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/recording_commands.rs) demonstrates this pattern, emitting `TranscriptUpdate` structs containing text sequences and timing data.

```rust
let update = TranscriptUpdate { text, sequence_id, timestamp };
if let Err(e) = app.emit("transcript-update", &update) {
    log::error!("Failed to emit transcript-update: {}", e);
}

```

## Frontend-to-Backend Command Invocation

While events flow from Rust to the UI, the reverse path uses Tauri's command system. The Next.js frontend invokes exposed Rust functions using `invoke` from `@tauri-apps/api/tauri`, triggering `#[tauri::command]` annotated handlers in the backend. These handlers execute audio capture logic and subsequently emit status updates back to the frontend, completing the bidirectional loop. The command registration occurs in [`frontend/src-tauri/src/lib.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/lib.rs), which serves as the entry point for all UI-to-Rust communication.

## React Context Listeners for Real-Time UI Updates

The frontend consumes events through React context providers that register Tauri event listeners during component initialization. This pattern centralizes state management and ensures consistent UI updates across the application.

### Recording State Context

Located in [`frontend/src/contexts/RecordingStateContext.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src/contexts/RecordingStateContext.tsx) (lines 140-154), this provider establishes listeners for `recording-started` and `recording-stopped` events. When Rust emits these events, the context updates its internal state, triggering re-renders in dependent components.

```tsx
import { listen } from '@tauri-apps/api/event';

// Inside RecordingStateContext.tsx
const unlisten = await listen<{ meeting_name: string }>(
  'recording-started',
  (event) => {
    setRecordingState(prev => ({ 
      ...prev, 
      active: true, 
      name: event.payload.meeting_name 
    }));
  }
);

```

### Transcript Context

The transcript streaming implementation in [`frontend/src/contexts/TranscriptContext.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src/contexts/TranscriptContext.tsx) (lines 287-295) registers a dedicated listener for `transcript-update` events. Each received payload appends to the transcript array, creating the live typing effect visible to users during meetings.

```tsx
const unlisten = await listen<TranscriptUpdate>('transcript-update', (e) => {
  setTranscript(prev => [...prev, e.payload.text]);
});

```

## The Complete Real-Time Communication Flow

Meetily's event architecture follows a predictable three-phase pattern:

1. **Initialization** – The user triggers `start_recording` via a UI button, which invokes the Tauri command registered in [`lib.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/lib.rs).
2. **Processing** – The Rust audio pipeline captures microphone and system audio, applies VAD filtering, and streams speech segments to Whisper. Each transcription result generates a `transcript-update` emit.
3. **Rendering** – React listeners in `TranscriptContext` and `RecordingStateContext` receive payloads, update their respective states, and propagate changes to UI components like the live transcript view.

## Error Handling and Reliability

The codebase implements defensive programming around event emission to prevent silent failures. When emitting events in [`recording_commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/recording_commands.rs), Rust code explicitly checks for errors and logs them using `log::error!`. This ensures that communication breakdowns between the Rust core and Next.js frontend are immediately visible in application logs rather than causing undefined UI behavior.

## Summary

- Meetily uses Tauri's native event system (`app.emit` and `listen`) to bridge Rust and TypeScript without HTTP overhead.
- Backend events originate in [`recording_commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/recording_commands.rs), broadcasting recording states and transcript chunks to the frontend.
- Frontend listeners in [`RecordingStateContext.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/RecordingStateContext.tsx) and [`TranscriptContext.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/TranscriptContext.tsx) translate these events into React state updates.
- The architecture supports bidirectional communication: TypeScript `invoke` calls trigger Rust commands, which then emit events back to update the UI.
- Robust error handling via `log::error!` ensures reliable real-time communication throughout the application lifecycle.

## Frequently Asked Questions

### What technology enables real-time communication in Meetily?

Meetily relies on Tauri's built-in event system rather than WebSockets or HTTP polling. The Rust backend uses `app.emit` to broadcast events, while the Next.js frontend consumes them using the `listen` function from `@tauri-apps/api/event`. This approach provides low-latency communication without requiring a separate network server.

### How does Meetily stream live transcript updates to the interface?

As the Whisper transcription engine processes audio, the Rust code in [`recording_commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/recording_commands.rs) emits `transcript-update` events containing `TranscriptUpdate` structs. The [`TranscriptContext.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/TranscriptContext.tsx) React provider listens for these events and appends each text chunk to the transcript state array, creating a real-time streaming effect in the UI.

### Is the communication between Meetily's frontend and backend bidirectional?

Yes. The frontend invokes Rust commands using Tauri's `invoke` API to initiate actions like starting recordings. The Rust handlers then execute the requested operations and emit events back to the frontend. This creates a full-duplex communication channel where both sides can initiate data transfer.

### How does Meetily prevent silent failures in event transmission?

The Rust codebase explicitly handles emission errors by checking the return value of `app.emit` calls and logging failures via `log::error!`. This pattern, visible in the transcript update emission logic within [`recording_commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/recording_commands.rs), ensures that any breakdown in the real-time communication channel is immediately recorded in application logs for debugging.