Docent
Reference

The Docent component

Every prop of the Docent component with its type and default, the hooks it provides, the events it emits, and the handle it puts on React context.

<Docent> from @usedocent/react mounts the guide and gives everything under it the handle.

Props

PropTypeDefaultWhat it does
appIdstringrequiredThe app this session belongs to, from the Console.
publishableKeystringrequireddk_pub_.... Ships in the browser and is restricted to the environment's allowed origins.
apiUrlstringrequiredOrigin of the Docent API, normally https://api.usedocent.com.
user{ id: string; traits?: Record<string, string | number | boolean> }requiredThe only identity the guide gets. id keys memory and placement.
userTokenstringnoneAn HS256 JWT your server signs with the environment's signing secret. When it verifies, the session is marked verified.
routerRouterAdapterpushState fallbackHow the guide navigates. See the framework guides.
presencePartial<Omit<PresenceOptions, 'appId' | 'user'>>noneOverrides for the mascot, such as palette and mascot. appId and user are set for you.
loadPresence(slug: string) => Promise<MascotFactory>noneLoads the presence the owner chose, by library slug. Omitted, every session gets Dot.
loadAudio(vendor: 'telnyx' | 'openai') => Promise<AudioModule>noneLoads the voice client for the vendor this session was granted. Omitted, startVoice() rejects with voice_unavailable.
nudgesNudgeOptions | falseonProactive, caption-only prompts with a per-session budget. false turns them off.
voice'tap' | 'off''off''tap' starts voice on the user's own first tap of the presence, and never before it.
onEvent(event: DocentEvent) => voidnoneRead live on every render, so an inline arrow is fine.
debugbooleanfalsePuts the handle on window.__docent.
childrenReactNodenoneYour app. It has to be children, not a sibling.

fetchImpl and WebSocketImpl also exist, for tests that need to stand in for the network.

The session is keyed on appId, publishableKey, apiUrl, user.id and userToken. Change one of those and the guide tears down and mints a new session. Everything else, the router adapter, loadAudio, loadPresence and onEvent included, is read live, so an inline object or arrow function does not remount anything.

Events

onEvent and useDocentEvent receive the same four:

EventFieldsWhen
handoffreason, route, transcriptThe guide passed the user to human support. The transcript is masked.
open_docsurl, title?The guide offered a documentation link.
goal_donegoalKeyA goal's done condition was met.
errorcode, messageSomething failed. Codes include mint_failed, voice_failed, presence_failed and whatever the server sent.
<Docent
  // ...
  onEvent={(event) => {
    if (event.type === 'handoff') openIntercom(event.transcript)
  }}
/>

Hooks

All of them are from @usedocent/react and all of them must be called under the component.

HookReturnsNotes
useDocent()DocentHandle | nullNull until the guide has mounted, which is one effect after first paint.
useDocentOrThrow()DocentHandleThrows instead of returning null, for call sites that would rather fail loudly.
useDocentEvent(cb)voidSubscribes without wiring an effect. The callback is held in a ref, so an inline arrow neither resubscribes nor goes stale.
useDocentState()DocentState | nullThe mascot's current state, polled every 200ms.
useDocentTrack()(event: string, payload?) => voidSafe to call before the guide has mounted.

The handle

What useDocent() returns:

MemberTypeWhat it is
presencePresenceHandleThe mascot and its overlay.
toolsToolsThe page tools: spotlight, point, scroll_to, navigate, act, plus clear and destroy.
sessionIdstring | nullNull until the session is minted.
readyPromise<void>Resolves when minting has finished, successfully or not.
ask(text)Promise<void>Sends a typed turn, as the composer does.
track(event, payload?)voidReports a goal event.
on(cb)() => voidSubscribes. Returns the unsubscribe.
startVoice()Promise<void>Asks for microphone consent the first time, then opens a call.
endVoice()Promise<void>Hangs up and releases the microphone.
destroy()voidTears everything down. The component calls this on unmount.

One example

'use client'

import { useDocent, useDocentEvent, useDocentTrack } from '@usedocent/react'

export const Toolbar = () => {
  const docent = useDocent()
  const track = useDocentTrack()

  useDocentEvent((event) => {
    if (event.type === 'goal_done') confetti(event.goalKey)
  })

  return (
    <button
      onClick={() => {
        track('asked_for_help')
        void docent?.ask('how do I invite a teammate')
      }}
    >
      Ask the guide
    </button>
  )
}

On this page