Docent

Quickstart

Ten steps from an empty Console to a working guide in your app, covering keys, the mount, markers, origins, knowledge, goals, presence and voice.

This is the whole install path, in order. The code is the Next.js App Router mount; the framework guides carry the same thing for React Router and for Vite with no router at all.

1. Get your keys

In the Console, create a workspace and an app. Setup provisions a development environment and shows you four things:

ValueLooks likeWhere it goes
App ida uuidBrowser, as appId
Publishable keydk_pub_...Browser, as publishableKey
Secret keydk_sec_...Your server and your CI only
API URLhttps://api.usedocent.comBrowser, as apiUrl

The secret key is shown once. Only its hash is stored, so copy it before you close the dialog. More in Environments and keys.

2. Install the packages

npm install @usedocent/react @usedocent/mascot @usedocent/sdk-audio-live @usedocent/sdk-audio

@usedocent/react is the binding. @usedocent/mascot carries the presences the owner can choose in the Console. The two audio packages are the voice clients, and neither is in your bundle until somebody taps the mascot: loadAudio below is a dynamic import, and only the vendor a given session was granted is ever fetched.

3. Mount the component

Render <Docent> once at the root of your app, wrapping it, inside any providers you already have. It has to wrap rather than sit beside, because useDocentTrack reads from React context and only children see it.

import { Docent } from '@usedocent/react'
import { useNextAdapter } from '@usedocent/react/next'
import { PRESENCE_LOADERS } from '@usedocent/mascot/library/loaders'

;<Docent
  appId={process.env.NEXT_PUBLIC_DOCENT_APP_ID!}
  publishableKey={process.env.NEXT_PUBLIC_DOCENT_PUBLISHABLE_KEY!}
  apiUrl="https://api.usedocent.com"
  user={{ id: user.id }}
  router={useNextAdapter(router, pathname, searchParams)}
  loadPresence={(slug) => PRESENCE_LOADERS[slug]?.() ?? Promise.reject(new Error(slug))}
  loadAudio={(vendor) =>
    vendor === 'openai' ? import('@usedocent/sdk-audio-live') : import('@usedocent/sdk-audio')
  }
  voice="tap"
>
  {children}
</Docent>

The mount above is the shape; the Next.js guide has the client component with router, pathname, searchParams and user declared.

user.id is whatever your own auth calls a user. It is the only identity the guide gets, and the key cross-session memory is stored under. Nothing else about the person is required.

voice="tap" starts voice on the user's own first tap of the mascot, never before it. The default is "off", which leaves a guide that types and never speaks.

Put the two public values in .env.local:

NEXT_PUBLIC_DOCENT_APP_ID=your-app-id
NEXT_PUBLIC_DOCENT_PUBLISHABLE_KEY=dk_pub_your_key
DOCENT_SECRET_KEY=dk_sec_your_key

The publishable key is safe in browser code: it only opens a session, and it works only from the origins you allow in step 5. DOCENT_SECRET_KEY has no NEXT_PUBLIC_ prefix on purpose: it is what the CLI uploads with, and it stays on the server.

4. Mark your UI

Six attributes. They are the whole annotation surface, and Markers is the full reference.

<button data-guide="create-project">New project</button>
<button data-guide="save" data-guide-allow="submit">Save</button>
<section data-guide-mask>
  <span data-guide-readable>Plan: Growth</span>
  <p>alex@acme.com</p>
</section>
<button data-guide-forbid>Delete workspace</button>
<a data-guide-primary href="/new">Start a project</a>

data-guide is a stable name Docent points at. data-guide-allow takes click, fill or submit, and submit is not implied by click. data-guide-mask keeps a subtree out of every snapshot, data-guide-readable re-exposes one child of it, data-guide-forbid makes an element untouchable, and data-guide-primary is the call to action the mascot keeps out of the way of.

5. Allow your origins

Console, Settings, Environments. The development environment starts with http://localhost:5173 and http://localhost:4173 allowed. Add whatever port your app runs on, or no session will start at all. An empty list stops the guide everywhere.

6. Teach it your product

Routes let the guide navigate. Knowledge lets it answer. Both upload with the CLI, and both authenticate with the secret key, so which environment you run this with matters: the route list belongs to that environment, and the knowledge pack belongs to the app it sits in.

npx @usedocent/cli sync ./src/app --docs ./docs --key dk_sec_...

If your documentation is a published site rather than Markdown in the repo, crawl it instead:

npx @usedocent/cli crawl https://docs.example.com --key dk_sec_...

A crawl publishes a new knowledge pack and replaces the current one, including a pack uploaded with sync. Run one or the other for an app, not both.

Then open the project map in the Console and use "Propose entries from knowledge" to draft a feature map entry per route, and accept the ones that are right. Details and every flag are in the CLI reference.

7. Declare goals

A goal is an outcome with a condition that says when it is done. Declare it in the Console, then fire it from your app where it actually completes:

import { useDocentTrack } from '@usedocent/react'

const track = useDocentTrack()
// ...
track('project_created', { projectId })

The goal key in the Console and the string you pass here are the same string. See Goals.

8. Choose a presence and a voice

Console, Presence picks the character your users see, out of Dot and fourteen others. Console, Voice picks what it sounds like. Both are stored per environment, so staging can try one before production does. See Presence and voice.

9. Verify

Load your app.

What you should see. The mascot arrives in a corner a moment after the page settles and opens its caption panel once with a first-run line. If you are on Dot, the default, its eyes follow your cursor while it is awake. Tapping it opens the panel; typing a question sends a turn and the answer streams back a word at a time. Ask it something that has an anchor, such as "where do I start a project", and a marker should land on the element you gave that data-guide name to. Drag the mascot and it snaps to the nearest corner and stays there on the next load. In the Console the dashboard counts the session and the turn within a minute.

Where to look when it does not.

What you seeWhat it usually is
No mascot at allUsually the environment variables. Log the three values at the mount: an undefined apiUrl mints against undefined/v1/sessions. Check the file is read and the names carry the NEXT_PUBLIC_ prefix.
The mascot appears, the panel says it cannot reach the guide serviceThe session mint failed. Subscribe with onEvent and read the error event: mint_failed with HTTP 403 is an origin that is not on the environment's allowed list, HTTP 401 is a key that does not match this app.
It answers "I do not know" to everythingNo knowledge pack. Run the sync or crawl from step 6 and watch the Console's Knowledge page for retrievable chunks.
It points at nothingThe anchor has moved. Docent resolves data-guide first at full confidence, then role and name, then visible text at 0.6, then position at 0.4. The default threshold is 0.6, so a text match is the weakest one that passes and a position-only match is refused; the tool then hands the model a description of where the thing is rather than pointing at the wrong element.
Nothing happens on a tap for voiceThe audio chunk failed to load or the grant was refused. The error event carries voice_failed with the reason.

onEvent is where all of that surfaces, so wire it while you are integrating:

<Docent
  // ...
  onEvent={(event) => {
    if (event.type === 'error') console.error('[docent]', event.code, event.message)
  }}
>

10. Go live

Console, Settings, Environments, Add environment, and pick production. It mints its own publishable and secret keys, shown once, and it starts with no allowed origins at all, so:

  1. Add your production origin, such as https://acme.com.
  2. Put the new publishable key and app id in your production environment variables.
  3. Run the sync again with the production environment's secret key. The route list is stored per environment, so production has none until you do. The knowledge pack is stored per app, so it is already there.
  4. Set the production environment's retention, between 0 and 90 days.

A production environment and a development environment share the app and its knowledge, and nothing else: separate keys, separate allowed origins, separate route lists, separate retention, separate presence and voice.

On this page