---
title: "Dictation and Text-Only Calls | Micdrop"
description: "Leave out the agent, the voice, or both, to build a dictation tool, a text-only assistant, or a call your own code drives."
url: "https://micdrop.dev/docs/server/dictation"
---

*   [Getting Started](/docs/getting-started)
*   [Client (Browser)](/docs/client)
    
    *   [Installation](/docs/client/installation)
    *   [React Hooks](/docs/client/react-hooks)
    *   [Start/Stop Call](/docs/client/start-stop-call)
    *   [Pause/Resume Call](/docs/client/pause-resume-call)
    *   [Mute/Unmute Call](/docs/client/mute-unmute-call)
    *   [Call State](/docs/client/call-state)
    *   [Display Conversation Messages](/docs/client/display-conversation-messages)
    *   [Handling Tool Calls](/docs/client/handling-tool-calls)
    *   [Device Management](/docs/client/devices-management)
    *   [Voice Activity Detection (VAD)](/docs/client/vad)
    *   [Turn Detection](/docs/client/turn-detection)
    *   [Reducing Latency](/docs/client/latency)
    *   [Error Handling](/docs/client/error-handling)
    *   Utility Classes
        
        *   [Mic](/docs/client/utility-classes/mic)
        *   [MicdropClient](/docs/client/utility-classes/micdrop-client)
        *   [MicRecorder](/docs/client/utility-classes/mic-recorder)
        *   [Speaker](/docs/client/utility-classes/speaker)
        
    
*   [Client (React Native)](/docs/react-native)
    
    *   [Installation](/docs/react-native/installation)
    *   [Hooks and Call State](/docs/react-native/hooks)
    *   [Audio Output and Devices](/docs/react-native/audio-output)
    *   [Voice Activity Detection (VAD)](/docs/react-native/vad)
    *   [Turn Detection](/docs/react-native/turn-detection)
    *   [Using Another Audio Library](/docs/react-native/custom-audio)
    
*   [Server (Node.js)](/docs/server)
    
    *   [Installation](/docs/server/installation)
    *   [With Fastify](/docs/server/with-fastify)
    *   [With NestJS](/docs/server/with-nestjs)
    *   [Auth and Parameters](/docs/server/auth-and-parameters)
    *   [First Message](/docs/server/first-message)
    *   [Dictation and Text-Only Calls](/docs/server/dictation)
    *   [Partial Messages](/docs/server/partial-messages)
    *   [Save Messages](/docs/server/save-messages)
    *   [Resume a Conversation](/docs/server/resume-conversation)
    *   [Recording Audio](/docs/server/recording-audio)
    *   [Error Handling](/docs/server/error-handling)
    *   [Tools](/docs/server/tools)
    *   [Extract Value from Answer](/docs/server/extract)
    *   [Auto End Call](/docs/server/auto-end-call)
    *   [Semantic Turn Detection](/docs/server/semantic-turn-detection)
    *   [Noise Filtering](/docs/server/noise-filtering)
    *   [Micdrop Protocol](/docs/server/protocol)
    
*   [AI Integrations](/docs/ai-integration)
    
    *   Provided Integrations
        
        *   [AI SDK](/docs/ai-integration/provided-integrations/ai-sdk)
        *   [Cartesia](/docs/ai-integration/provided-integrations/cartesia)
        *   [ElevenLabs](/docs/ai-integration/provided-integrations/elevenlabs)
        *   [Gladia](/docs/ai-integration/provided-integrations/gladia)
        *   [Gradium](/docs/ai-integration/provided-integrations/gradium)
        *   [Kokoro](/docs/ai-integration/provided-integrations/kokoro)
        *   [Mistral](/docs/ai-integration/provided-integrations/mistral)
        *   [OpenAI](/docs/ai-integration/provided-integrations/openai)
        *   [Piper](/docs/ai-integration/provided-integrations/piper)
        *   [Pocket TTS](/docs/ai-integration/provided-integrations/pocket-tts)
        *   [Whisper](/docs/ai-integration/provided-integrations/whisper)
        
    *   Custom Integrations
        
        *   [Agent (LLM)](/docs/ai-integration/custom-integrations/custom-agent)
        *   [Speech-to-Text (STT)](/docs/ai-integration/custom-integrations/custom-stt)
        *   [Text-to-Speech (TTS)](/docs/ai-integration/custom-integrations/custom-tts)
        
    *   Fallback Strategies
        
        *   [FallbackAgent](/docs/ai-integration/fallback-strategies/agent-fallback)
        *   [FallbackSTT](/docs/ai-integration/fallback-strategies/stt-fallback)
        *   [FallbackTTS](/docs/ai-integration/fallback-strategies/tts-fallback)
        
    *   [Local Models](/docs/ai-integration/local-models)
        
        *   [Choosing the Models](/docs/ai-integration/local-models/choosing-models)
        *   [Latency and Memory](/docs/ai-integration/local-models/performance)
        *   [Explorations](/docs/ai-integration/local-models/explorations)
        
    *   [IA Vocale Souveraine 🇫🇷🇪🇺](/docs/ai-integration/sovereign-voice-ai)
    
*   [Migration](/docs/migration)
    
    *   [Upgrade to v3](/docs/migration/v3)
    

[Micdrop](/) › [Documentation](/docs/getting-started) › [Server (Node.js)](/docs/server)

# Dictation and Text-Only Calls

`agent` and `tts` are optional. Leaving one of them out changes what a call does, while the microphone, the voice activity detection and the transport keep working the same way.

Configuration

What the user gets

`stt + agent + tts`

A full spoken conversation

`stt + agent`

An assistant that answers in writing

`stt`

Dictation, with nothing answering back

`stt + tts`

A call your own code drives, speaking when it decides to

## Dictation

With a speech to text alone, the call transcribes and stays quiet. Each sentence reaches the client as a message, exactly as a user message does in a full conversation.

```
import { MicdropServer } from '@micdrop/server'import { GladiaSTT } from '@micdrop/gladia'
new MicdropServer(socket, {  stt: new GladiaSTT({ apiKey: process.env.GLADIA_API_KEY }),})
```

The client displays them from `conversation`, like any other message:

```
Micdrop.on('StateChange', (state) => {  const text = state.conversation    .filter((message) => message.role === 'user')    .map((message) => message.content)    .join(' ')  textarea.value = text})
```

Each sentence lands once the speech to text has settled it, so the text grows sentence by sentence, at the pauses.

The [dictation example](https://github.com/Godefroy/micdrop/tree/main/examples/dictation) does exactly this, in a page with a microphone button, a language picker and a text area.

## An assistant that writes instead of speaking

Without a text to speech, the agent still answers, and its answer reaches the client as a message. Nothing is synthesized, so nothing plays.

```
new MicdropServer(socket, {  stt,  agent: new OpenaiAgent({    apiKey: process.env.OPENAI_API_KEY,    systemPrompt: 'You are a helpful assistant',  }),})
```

The client leaves its processing state as soon as the answer is complete, and `isAssistantSpeaking` stays false for the whole call, since no voice ever plays.

Turn on [`partialMessages`](/docs/server/partial-messages) to stream the answer as it is written, which is what makes a text answer feel as immediate as a spoken one.

## Driving the conversation yourself

A call with a voice and no agent speaks only when your code asks it to. This is the shape to reach for when the answers come from a state machine, a workflow engine, or an orchestration framework you already run.

```
const server = new MicdropServer(socket, { stt, tts })
server.on('Message', async (message) => {  if (message.role !== 'user') return  const answer = await myOwnOrchestrator(message.content)  server.speak(answer)})
```

`speak()` accepts a string or a stream of text. Given a string, it also records the sentence in the conversation, since no agent is there to do it.

## Reading the conversation

`server.conversation` holds everything said, whether an agent keeps it or the server does, and stays readable once the call is over.

```
const server = new MicdropServer(socket, { stt })
server.on('End', ({ conversation, duration }) => {  console.log(`${conversation.length} sentences in ${duration}s`)})
```

The `Message` event fires for every message added on either side. See [Save Messages](/docs/server/save-messages) for storing them as they arrive.

With an agent, the conversation opens with the system message that carries the prompt. Without one, it holds nothing but what was said.

## What still needs an agent

`generateFirstMessage` asks the agent for its opening line, so it does nothing without one. A static `firstMessage` works either way, and is spoken when a text to speech is configured.

Tools, [automatic call ending](/docs/server/auto-end-call), [extraction](/docs/server/extract) and [semantic turn detection](/docs/server/semantic-turn-detection) are agent features, and are out of reach in a call that has no agent.

[Previous← First Message](/docs/server/first-message)[NextPartial Messages →](/docs/server/partial-messages)

On this page

*   [Dictation](#dictation)
*   [An assistant that writes instead of speaking](#an-assistant-that-writes-instead-of-speaking)
*   [Driving the conversation yourself](#driving-the-conversation-yourself)
*   [Reading the conversation](#reading-the-conversation)
*   [What still needs an agent](#what-still-needs-an-agent)
