This guide walks you through the steps to integrate the Dictation SDK into your application.What will you do
Install the Dictation SDK package for your framework (JavaScript or React)
Create a SukiAuthManager from @suki-sdk/core with your partner token and provider fields
Create a DictationClient from @suki-sdk/dictation with your auth manager
Mount the Dictation UI into your application using the encounter object.
Using an AI coding tool?Copy the following prompt to add the Suki developer documentation as a skill and MCP server to your tool for better AI-assisted coding during the integration process.
Install the Suki developer docs as skill to get context on Suki’s developer tools, APIs, and SDKs.npx skills add https://developer.suki.aiThen add the Suki developer docs MCP server for access to documentation search. Follow the MCP instructions at https://developer.suki.ai/documentation/mcp.
The Dictation SDK works best when you treat authentication and the dictation client as long-lived objects for a page or session. You should only change the specific field or surface receiving the dictation. This approach ensures that token refreshes and iframe setups remain predictable while avoiding duplicate overlays.A common mistake is to build a new DictationClient on every React render (for example, in the component body without useMemo) or to use a separate client for each text field. The SDK assumes one client per page scope. If you do not follow this pattern, the session and iframe will frequently tear down and restart. This creates an unstable experience for the user.
Initialize once per session and reuse:
Suki Auth Manager
Create SukiAuthManager from @suki-sdk/core after the partner token is available.
Dictation Client
Create DictationClient with that authManager. Reuse this client across dictation fields.
Dictation Provider (React only)
In React, wrap components with DictationProvider from @suki-sdk/dictation-react.
Dictation Per Active Field
Show the dictation UI per field or scratchpad. Avoid recreating DictationClient on every render or per field.
The JavaScript and React tabs under Your first dictation session below mirror this pattern: one auth manager, one client, then show() or <Dictation> for the active target only.
Each dictation instance needs a stable, uniquefieldId. The SDK sends it back on every callback with text, so you can route results to the right control.
A common pattern is to match the target input’s HTML id. Refer to Field IDs section in Configuration guide for more details.
Apply Recommended integration pattern above: build SukiAuthManager and DictationClient once, then open dictation only for the target that should be active.For JavaScript, give dictation a container (rootElement) with real height. Example markup:
Create the auth manager and client once, then call show() when the user should dictate (for example after a button click). Use try / catch so configuration or auth errors surface in your logs.
JavaScript
import { SukiAuthManager } from "@suki-sdk/core"; // Step 1: Create the auth managerimport { DictationClient } from "@suki-sdk/dictation"; // Step 2: Create the clientconst authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required environment: "staging", // optional - default is "production" loginOnInitialize: true, // optional - default is false providerName: "John doe", // optional - default is empty providerOrgId: "1234", // optional - default is empty providerId: "1234567890", // optional - default is empty providerSpecialty: "FAMILY_MEDICINE", // optional - default is empty});const client = new DictationClient({ authManager }); // Step 3: Create the clientasync function startDictation() { try { await client.show({ mode: "in-field", // required - you must set this as per your use case fieldId: "clinical-notes", // required - you must set this to the ID of the textarea you want to dictate rootElement: document.getElementById("dictation-root"), // required - you must set this to the ID of the div you want to contain the dictation iframe initialText: document.getElementById("clinical-notes")?.value ?? "", // optional - you can set this to the initial text of the textarea onSubmit: ({ fieldId, text }) => { const el = document.getElementById(fieldId); if (el) el.value = text; }, onCancel: ({ fieldId }) => { console.log("Cancelled", fieldId); }, }); } catch (err) { console.error(err); }}// Call startDictation() from your UI when ready.
Your integration is working when the dictation UI appears inside dictation-root, you can dictate, and text you commit is written to the textarea in onSubmit.
For optional settings and callbacks (onDraft, initialText, scratchpad mode, and more),
refer to Configuration. For iframe or layout problems, refer to Error handling guide for more details.
Create DictationClient once (useMemo), wrap the tree with DictationProvider, and render <Dictation> only when that field should own the session. Unmounting <Dictation> calls hide() for you.
React
import { useMemo, useState } from "react";import { SukiAuthManager } from "@suki-sdk/core"; // Step 1: Create the auth managerimport { DictationClient } from "@suki-sdk/dictation"; // Step 2: Create the clientimport { DictationProvider, Dictation } from "@suki-sdk/dictation-react"; // Step 3: Wrap the tree with DictationProviderexport function NotesWithDictation() { const client = useMemo(() => { const authManager = new SukiAuthManager({ partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required environment: "staging", // optional - default is "production" loginOnInitialize: true, // optional - default is false providerName: "John doe", // optional - default is empty providerOrgId: "1234", // optional - default is empty providerId: "1234567890", // optional - default is empty providerSpecialty: "FAMILY_MEDICINE", // optional - default is empty }); return new DictationClient({ authManager }); // Step 4: Create the client }, []); // Step 5: Create the client once and reuse it across fields const [notes, setNotes] = useState(""); const [dictationActive, setDictationActive] = useState(false); return ( <DictationProvider client={client}> <textarea id="clinical-notes" value={notes} onChange={(e) => setNotes(e.target.value)} /> <button type="button" onClick={() => setDictationActive((v) => !v)} > {dictationActive ? "Stop dictation UI" : "Start dictation"} </button> {dictationActive && ( <Dictation fieldId="clinical-notes" mode="in-field" // required - you must set this as per your use case initialText={notes} // optional - you can set this to the initial text of the textarea onSubmit={({ text }) => setNotes(text)} onCancel={() => setDictationActive(false)} /> )} </DictationProvider> );}
Your integration is working when turning dictation on shows the hosted UI, committed text updates notes through onSubmit, and only one<Dictation> is mounted at a time for that shared client.