This guide walks you through the process of integrating the Suki Web SDK for audio dictation in a React application (browser-based) using the React package provided by Suki.You will create Auth Manager and Dictation Client (typically inside useMemo so they are not recreated every render), wrap your tree with Dictation Provider, and render Dictation when the user should dictate.Let’s get started!
Add all three packages to the same project you load in the browser:
pnpm add @suki-sdk/core @suki-sdk/react
After you install, pull the SDK into your files with import, the same way as in the examples below. Use whatever approach your project already uses for other npm libraries.
For this example we will assume you are using in-field mode as your preferred mode.In in-field mode you need two parts in the UI: a div (or similar) that you can pass as rootElement, where the dictation controls show up, and a textarea (or input) that onSubmit will update when the user finishes.The dictation layer matches the size ofrootElement when you set it, so that node should have a height you control. Refer to Wrapper layout guide for recommended markup and CSS.Code example for container and field layout
Now you need to create the Auth Manager for your application. In order to create the Auth Manager, you must have the partnerId and partnerToken credentials from Suki.Refer to Partner onboarding guide to learn how to get these credentials.In React you usually create the auth manager inside the same useMemo as the dictation client (see Step 3), so both exist once per page or shell. The snippet below shows only the auth piece for clarity.Code example for creating auth manager
JavaScript
import { SukiAuthManager } from "@suki-sdk/core";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: "staging" | "production" loginOnInitialize: true, // optional: sign in as soon as this runs autoRegister: false, // optional: enable provider auto-registration providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty});
After you have created the auth manager, you can create the dictation client for your application. The Dictation Client is the object the React components use under the hood.Create one dictation client and reuse it for the whole tree under DictationProvider. Use useMemo with an empty dependency array so you do not run new DictationClient(...) on every render.Code example for creating dictation client in React
React
import { useMemo } from "react";import { SukiAuthManager } from "@suki-sdk/core";import { DictationClient } from "@suki-sdk/react";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: "staging" | "production" loginOnInitialize: true, // optional: sign in as soon as this runs autoRegister: false, // optional: enable provider auto-registration providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty }); return new DictationClient({ authManager });}, []);
Pass the client from Step 3 into DictationProvider. Every component that renders <Dictation> must be a child of that provider.Code example for wrapping with DictationProvider
React
import { DictationProvider } from "@suki-sdk/react";export function App() { const client = useMemo(/* ... Step 3 ... */, []); return ( <DictationProvider client={client}> {/* children that render <Dictation /> */} </DictationProvider> );}
You can put DictationProvider at app root or only around the screen that needs dictation.
Render <Dictation> only while that field should own the session (for example when the user clicked “Start dictation”). When <Dictation> unmounts, the SDK calls hide() for you.Pass mode, fieldId, initialText, onSubmit, and any optional props you need. Refer to Configuration guide for more details on the available options and how to use them.Code example for rendering Dictation in React
Props such as onSubmit, onCancel, and onDraft receive the same shape as in the JavaScript API:
React
{ fieldId: string,text: string}
Refer to Callbacks guide for more details on the available callbacks and how to use them.
You do not poll for text; the SDK calls your functions when the user commits or cancels, and may call onDraft when they move on without submitting (refer to Callbacks guide for more details).
Use the same client and DictationProvider. Change which field is active by updating state (for example activeFieldId) so only one <Dictation> is mounted, or swap fieldId / initialText on the next mount. You do not need to call hide() yourself just to move from one field to another when unmounting one <Dictation> and mounting another is how your UI switches.
Below is a complete code example in React for in-field mode with DictationProvider, a toggle button, and one field.
React
import { useMemo, useState } from "react";import { SukiAuthManager } from "@suki-sdk/core";import { DictationClient } from "@suki-sdk/react";import { DictationProvider, Dictation } from "@suki-sdk/react";export 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: "staging" | "production" loginOnInitialize: true, // optional: sign in as soon as this runs autoRegister: false, // optional: enable provider auto-registration providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty }); return new DictationClient({ authManager }); }, []); 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" : "Start dictation"} </button> {dictationActive && ( <Dictation fieldId="clinical-notes" mode="in-field" initialText={notes} 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 client.
Reuse one dictation client. Build a single DictationClient inside useMemo (or equivalent) for the page or shell. Creating a new client on every render breaks that pattern and often resets the hosted UI.
Reuse one auth manager. Create SukiAuthManager once inside the same useMemo as the client, as in the steps above.
Handle when the user commits. You must pass onSubmit so the SDK can deliver the final text. Without it, dictation often closes right after the user tries to finish.
Pick a clear field label. Each session needs a stable, unique fieldId in callbacks. Using the same value as the target input’s id is a simple way to know which element to update. Refer to Field IDs guide for more details.
Give the dictation host real height. The node you use for rootElement (when you set it) should have height you control. Otherwise the dictation area can look blank. Refer to Error handling and In-field mode guides for more details.
One active Dictation at a time. Use boolean state or activeFieldId so you do not mount multiple dictation surfaces against the same client at once.
Rely on unmount for hide. Removing <Dictation> is the normal way to tear down the UI; you usually do not call hide() yourself in React.