Deploying
A second desk shows the first desk's conversations
A second desk shows the first desk's conversations
jun-desk database, jun-desk-files bucket and jun-desk-crawl queue.Give every desk in an account its own names on the Deploy button’s form, for example jun-trial, jun-trial-files and jun-trial-crawl. For a command-line deploy, change database_name, bucket_name and both queue names in wrangler.jsonc before the first npm run deploy. See Deploy to Cloudflare.Setup refuses the setup token
Setup refuses the setup token
SETUP_TOKEN isn't configured means the Worker has no SETUP_TOKEN secret, or it’s shorter than 16 characters. Set it (see Secrets and settings) and reload.That setup token is wrong means what you typed doesn’t match the secret exactly. Secrets can’t be read back; if you’ve lost it, set a new value and use that.A new version fails after upgrading
A new version fails after upgrading
npm run deploy, never wrangler deploy alone: npm run deploy builds, applies new database migrations, and only then deploys the new code. If you ran wrangler deploy directly, run npx wrangler d1 migrations apply DB --remote now. See Upgrade.AI replies fail with error 1102
Symptom: on the Workers Free plan, AI replies and the Agent page’s AI chats fail now and then, and Cloudflare’s logs show error 1102 (Worker exceeded resource limits). Cause: the Free plan gives a Worker 10 ms of CPU time per request. Reading an AI model’s streamed answer takes far more: 0.3 to 1 second was measured for one widget edit. The Workers Paid plan ($5 a month) allows 30 seconds by default. Fix: move the account to Workers Paid. Everything else (the inbox, the widget, the visitor list) runs on the Free plan. See Costs and limits and Cloudflare’s Workers limits.Signing in
Passkeys stop working after a domain change
Passkeys stop working after a domain change
jun-desk.<you>.workers.dev to support.acme.com (or the other way), the browser has no passkey for the new address.- Owner: open
https://<new address>/recover, enter the setup token, and create a passkey there. - The old address keeps working as long as the Worker still answers on it, so everyone can keep signing in there.
I lost every passkey
I lost every passkey
/recover on your desk and enter the setup token. It registers a new passkey for the owner’s account.A teammate who lost theirs needs an owner or admin to remove them in Settings → Team and send a new invite. They join as a new account.The invite link doesn't work
The invite link doesn't work
The widget
The launcher doesn't appear
The launcher doesn't appear
Jun: no data-keyin the console: the tag has nodata-key. Copy the snippet again from Chat widget → Install.- The tag is an ordinary
<script src>tag. The loader finds its own tag throughdocument.currentScript, which doesn’t exist fortype="module"scripts or code thatevals it. Don’t bundlewidget.js; load it from your desk. - Your site’s Content Security Policy blocks the desk. The console shows
Refused to load the script…orRefused to connect…. Allow your desk’s origin inscript-src,connect-src(withwss://too),frame-srcandimg-src. See Widget options. - The tag is in the page. Check the served HTML (View Source), not just your template: some frameworks drop tags they don’t manage.
The launcher appears but the chat stays blank or won't load
The launcher appears but the chat stays blank or won't load
- Allowed websites: with sites listed under Chat widget → Behaviour → Allowed websites, the chat frame refuses to load anywhere else. The console shows
Refused to frame … because an ancestor violates … frame-ancestors. Add the site’s hostname, or*.acme.comfor every subdomain (that coversacme.comtoo).localhostneeds its own entry if you test there. - Wrong key: the key must be the one shown on your desk. A key from another desk doesn’t work.
- Ad and privacy blockers can block third-party frames and sockets. Try a clean browser profile.
Visitors don't show on the Visitors page
Visitors don't show on the Visitors page
- With
data-consent="required", a visitor appears only after your page callsJunDesk.consent(true). - With Allowed websites set, the site must be on the list.
- A visitor with no activity for 75 seconds (a closed tab, a sleeping laptop) drops off the list.
No errors or failed requests show in the conversation
No errors or failed requests show in the conversation
data-capture="off"turns capture off.- Errors that happen before the loader runs aren’t seen. Put the tag in
<head>, before your own scripts. - Capture is in memory and sent with the visitor’s message, so a full page reload before they write clears it.
- Bodies, typed values and query values are never captured, by design. See Debug context.
Page actions
The AI never offers my page actions
The AI never offers my page actions
- Load order. The tag must be in
<head>, withdefer, before your app’s scripts. Withasync, or with the tag after your bundle, code that checks fordocument.modelContextonce on load can run first, find nothing and register nothing. - Registering before the loader runs. Call
window.JunDesk?.registerAction(…)only once the loader exists, or wait for itsjundesk:readyevent onwindow. The React hookuseJunActionwaits for you. pages. An action withpages: ["/pricing"]is offered only on those paths. Check the path the visitor is on.available. An action whoseavailable()returns false isn’t offered.- Too many actions. At most 30 are offered per reply, picked by the visitor’s words and what’s on screen, from at most 60 the loader sends.
- The desk sees the list when the visitor writes. Send a message from the page, then check Agent → Actions → On your website: it lists every action the desk has seen.
An action always asks for confirmation, or never does
An action always asks for confirmation, or never does
risk sets the default (confirm unless you say otherwise). The desk’s choice under Agent → Actions → On your website (stored in website-actions.yaml) overrides it: auto, confirm or human.The AI
The AI doesn't answer
The AI doesn't answer
ChatGPT sign-in on a deployed desk ends on a page that doesn't load
ChatGPT sign-in on a deployed desk ends on a page that doesn't load
http://127.0.0.1, so on a deployed desk the browser ends on an address like http://127.0.0.1:1455/auth/callback?code=… that doesn’t load.- Copy the whole address from the browser’s address bar.
- Go back to the desk’s tab and paste it into the box the sign-in step shows.
- Do it within 10 minutes of pressing Sign in with ChatGPT; after that, start again.
That isn't the sign-in return address means you pasted something else: the address must contain /auth/callback?code=. Locally (npm run dev), the sign-in returns to the desk on its own.ChatGPT sign-in spends your own ChatGPT plan. OpenAI’s terms cover plan usage for your own use, not a desk answering the public. See Models.The AI answers from outdated docs
The AI answers from outdated docs
Knowledge and crawling
A website source ends with "No readable pages"
A website source ends with "No readable pages"
No readable pages. Last error: … names the last page that failed and why. Common causes:- The pages are drawn by JavaScript. The crawler reads the HTML the server sends; it doesn’t run scripts. A single-page app that renders in the browser has no text to read. Point it at a server-rendered docs or help site, or add the content as files or snippets.
robots.txtdisallows the paths. The crawler (user agentJunDeskBot) followsDisallowrules.- The server blocks bots or returns errors (a firewall, a login wall, rate limits).
- The responses aren’t HTML. Only
text/htmlpages are read.
The crawl misses pages
The crawl misses pages
- Scope: only pages on the same origin and under the starting address’s folder are crawled. Starting at
https://acme.com/docs/covers/docs/…, not/blog/…. - Sitemap first: the crawler reads
sitemap.xml(and sitemaps listed inrobots.txt). Without one, it follows links from the start page, up to 3 links deep. - Page limit: each website source stops at its page limit (200 by default, set when you add it).
Crawling fails in local development
Crawling fails in local development
localhost:5173 fails. Crawl a public URL instead.Files are found only by keyword
Files are found only by keyword
Notifications
No push notifications on iPhone or iPad
No push notifications on iPhone or iPad
Notifications don't arrive while the desk is open
Notifications don't arrive while the desk is open
The jun CLI
"This API token isn't valid" or "belongs to another workspace"
"This API token isn't valid" or "belongs to another workspace"
jun login again (or update JUN_DESK_TOKEN in CI)."Only owners and admins can change the agent"
"Only owners and admins can change the agent"
jun push needs an owner or admin; the token acts as whoever created it. pull and eval work for any member."Someone edited the agent in the dashboard since your last pull"
"Someone edited the agent in the dashboard since your last pull"
pull. Run jun pull, merge with git, and push again. See Agent as code.Still stuck
Search or open an issue on GitHub. Include what you did, what you expected, and any error message orcode from the API response. Cloudflare’s logs for the Worker (Workers & Pages → your Worker → Logs) often show the cause.