Skip to main content

OttoBot

OttoBot is a per-organization chat surface inside Phoenix. Unlike the public OttoBot at phoenix.hginsights.com/ottobot — which is shared and runs against generic data — your org's OttoBot is tuned to your Salesforce, your Confluence, your persona. It uses your members' Phoenix identities, so what each user sees respects the access controls you've already set up in Phoenix.

Quick start

Once OttoBot is enabled for your organization, you'll find it in the Phoenix sidebar at:

https://phoenix.hginsights.com/organizations/<your-org-slug>/ottobot

If you don't see "OttoBot" in your sidebar, OttoBot is not enabled for your organization yet — see Requesting activation below.

Sending your first message

  1. Click OttoBot in the sidebar (or navigate directly to the URL above).
  2. Type a question in the input box and press Send. A few starter prompts are listed under the empty state to give you an idea of what kinds of questions OttoBot is good at.
  3. The response streams back token-by-token. Markdown is rendered (tables, lists, bold, links).
  4. To start a fresh question, just send another message — OttoBot replaces the in-progress stream cleanly.

Example prompts

OttoBot is most useful for questions that span your org's data:

  • "What were our top accounts last quarter?"
  • "Show me technographic data for Cisco."
  • "Summarize this week's pipeline movement."

Requesting activation

OttoBot is provisioned per-org, on request. To request activation for your organization:

  1. Email Phoenix@hginsights.com with your org name and a brief description of what you'd like OttoBot to be tuned for (your CRM? your knowledge base? both?).
  2. Alternatively, talk to your Customer Success Manager — they'll route the request to the Phoenix team.

The Phoenix team will enable OttoBot for your organization, register it in Phoenix, and email you when it's ready. Typical turnaround is 1–2 business days.

Until activation lands, navigating to /organizations/<your-org-slug>/ottobot shows an "OttoBot is not enabled for <your-org>" page with the same email address.

Who can use it

  • Org members. Anyone on your team who already has access to your Phoenix organization can use OttoBot. There's no separate seat or per-user setup.
  • Not org members. Users who aren't members of your org get redirected to the Phoenix home page if they navigate to your org's OttoBot URL — they never see chat content or even confirmation that it exists.
  • Read-only superadmins. Phoenix superadmins who are temporarily "acting as" your org without being a member see a notice on the dashboard rather than the chat UI. OttoBot acts on real user identity, and the read-only acting-as mode doesn't have a per-user data context.

What OttoBot can and can't do

Can:

  • Answer questions grounded in your org's data (whatever data sources your org has connected to Phoenix).
  • Render markdown responses — tables, lists, links.
  • Stream long answers progressively.

Can't (today):

  • Carry conversation history across sessions. Each message is standalone for now — conversation memory is on the roadmap.
  • Be embedded in your own application yet — that's coming in a separate phase (see iframe embedding below).

Privacy & access control

OttoBot calls Phoenix MCP on your behalf, using your Phoenix identity. That means:

  • Anything OttoBot can answer, you can already see in Phoenix.
  • Org members can't see another member's private data through OttoBot — the same access controls Phoenix enforces elsewhere apply here.
  • Chat content is not shared across orgs. Every request is scoped to your organization, and your org's data, persona, and traces are kept separate from other organizations'. For how that separation is enforced, see OttoBot Security.

Error messages

What you seeWhat it meansWhat to do
"Your session expired — please refresh the page."Your Phoenix session timed out mid-chat.Reload the page; you'll be prompted to sign in again.
"You don't have access to this organization's OttoBot."You're signed in but not a member of the org in the URL.Sign in with the right account, or ask an admin to add you.
"Sending too fast — wait a moment and try again."You've hit the per-user rate limit (50 chats/minute).Wait a few seconds; the limit resets quickly.
"OttoBot is temporarily unavailable. Please try again in a few minutes."The OttoBot service isn't responding right now.Wait a few minutes; if it persists, email Phoenix@hginsights.com.

Embedding OttoBot in your own application

You can put OttoBot inside your own internal portal, CRM, or intranet page with an <iframe>. Embedding is off by default: Phoenix only allows sites you have explicitly registered, so an unregistered page gets a blank frame rather than a working chat.

1. Register your origin

Email Phoenix@hginsights.com with the exact origin of every page that will embed OttoBot.

An origin is scheme://host[:port] — no trailing slash and no path:

Origin
https://portal.acme.com
https://portal.acme.com:8443✅ (non-default port)
https://portal.acme.com/❌ trailing slash
https://portal.acme.com/intranet❌ includes a path
portal.acme.com❌ no scheme

Matching is exact. https://acme.com and https://www.acme.com are different origins — register each one you actually embed from, including any staging hosts.

2. Add the iframe

<iframe
src="https://phoenix.hginsights.com/organizations/YOUR_ORG_SLUG/ottobot"
width="100%"
height="560"
title="OttoBot"
></iframe>

If your users are already signed in to Phoenix in the same browser, you're done — the iframe uses their existing session, and each user sees only what their Phoenix permissions allow.

3. Authenticate users who have no Phoenix session

If the people using your portal don't sign in to Phoenix directly, your backend exchanges your organization's API key for a short-lived chat token and passes that token to the iframe.

Your API key must never appear in browser code. Mint the token server-side:

// YOUR BACKEND
const res = await fetch("https://phoenix.hginsights.com/api/ottobot/embed-token", {
method: "POST",
headers: {
"x-api-key": process.env.PHOENIX_API_KEY,
"content-type": "application/json",
},
body: JSON.stringify({ organizationSlug: "YOUR_ORG_SLUG" }),
});

const { token, expiresAt } = await res.json();

The organizationSlug must match the organization your API key belongs to; a mismatch returns 403 and issues no token.

Attributing sessions to individual end users

By default every token minted this way carries the identity of the Phoenix user who owns the API key. That means all of your users share one identity: their chat history is attributed to the same person, and they share a single rate-limit budget.

To attribute each session to the person actually chatting, add endUserEmail:

body: JSON.stringify({
organizationSlug: "YOUR_ORG_SLUG",
endUserEmail: "person@yourcompany.com",
}),

Each end user then gets their own attribution and their own rate-limit budget (50 requests per minute), so one heavy user can no longer slow everyone else down.

Two limits also apply to your API key as a whole, shared across all of your end users:

LimitApplies to
100 requests per minuteToken requests that name an endUserEmail
500 requests per minuteAll token requests from the key, attributed or not

So the attributed path is bounded by the lower of the two — in practice 100 per minute per key, whatever the per-end-user budget allows. The tighter limit exists because resolving an address to a Phoenix user is a more expensive lookup than issuing a token.

Tokens last about five minutes, so the usual fix for hitting either ceiling is to mint one token per end user per session and reuse it, rather than one per page load. Get in touch if you need either limit raised.

The address must already belong to a Phoenix user who is a member of your organization. Phoenix never creates accounts from this call and never takes your word for who someone is — invite the person to your Phoenix organization first, in the same way you would any other member. If the address doesn't match a Phoenix user in your organization, the call returns 403 and issues no token.

note

A 403 here deliberately doesn't tell you why — "no such Phoenix user" and "not a member of this organization" return exactly the same response. That's intentional: it stops the endpoint being used to discover which email addresses have Phoenix accounts. If you're troubleshooting, check the member list for your organization in Phoenix.

Omit endUserEmail entirely and the call behaves exactly as it did before, minting for the API key's owner — existing integrations need no changes.

Then hand the token to the iframe from your page:

// YOUR PAGE
frame.contentWindow.postMessage(
{ type: "phoenix-auth", token },
"https://phoenix.hginsights.com", // always target the exact origin, never "*"
);

Tokens are valid for about five minutes. For a session that stays open longer, mint a fresh token and post it again before the previous one expires:

setInterval(deliverToken, 4 * 60 * 1000);

Security notes

  • Your API key stays on your server. The token that reaches the browser can only chat, expires in minutes, and is revocable.
  • Always target the exact Phoenix origin in postMessage. Using "*" would broadcast the token to any frame that happens to be listening.
  • Only registered origins can embed. Phoenix sends a frame-ancestors policy naming your registered origins; browsers refuse to render the frame anywhere else.
  • Only Phoenix members can be named. endUserEmail selects an existing member of your organization — it cannot create one, and it cannot reach a user in someone else's organization. Deliver each token only to the person it was minted for: it carries that user's identity for its lifetime.

Embedding troubleshooting

The frame is blank and the browser console says "Refused to display … frame-ancestors". Your origin isn't registered, or it doesn't match byte-for-byte. Compare the console's reported origin against what you sent us — http vs https and www vs bare are the usual culprits.

The chat loads but every message returns 401. The token expired or was never delivered. Confirm your page posts the token after the iframe's load event, and that you re-mint before the five-minute expiry.

The token request returns 403. Check the code in the response body — there are three causes:

  • org_mismatch — the organizationSlug in the request body doesn't match the organization your API key belongs to.
  • end_user_not_eligible — the endUserEmail you supplied isn't a Phoenix user who belongs to that organization. Either the address has no Phoenix account, or it has one but isn't a member of this org; the response deliberately doesn't distinguish the two, so check your organization's member list in Phoenix.
  • ottobot_not_enabled — OttoBot isn't switched on for that organization. Email Phoenix@hginsights.com.

The token request returns 429. You've hit one of the key-level ceilings described above — 100/min for requests naming an endUserEmail, or 500/min overall. Mint one token per end user per session and reuse it for its ~5-minute lifetime rather than minting per page load.

Troubleshooting

The sidebar doesn't show "OttoBot" for me. It's only surfaced when OttoBot is enabled for the org in your current URL. Either activation hasn't been completed yet (email Phoenix@hginsights.com) or you're navigating in a different org's context — check the org switcher at the top of the sidebar.

I see the chat UI but every message returns "temporarily unavailable". The OttoBot service is down or unreachable. Email Phoenix@hginsights.com with the time of the failure and we'll investigate.

A response includes garbled markdown. OttoBot streams responses progressively; partial markdown can look odd until the full response arrives. If a completed response still looks wrong, email us with a screenshot.