@sitegpt/convex is the SiteGPT component for Convex apps. It calls API v2 from your Convex backend. Use it when your app runs on Convex and you want to:
- Get answers on the server. Call
sitegpt.ask()in a Convex action. You get the chatbot’s answer back, for example for an “Ask AI” box in your app. - Keep content in sync. Call
sitegpt.syncDocument()in the same mutation that writes your data. The chatbot’s content then follows your Convex table. When you delete the row, the chatbot forgets it.
This component runs in your Convex backend. To show the chat widget on your website, see Add the chatbot to your website.
Before you start
- Plan: API access is available on the Growth plan and above. See Plans and limits.
- API token: Create a token on the Agents page. Give it the scopes for the methods you use. See Scopes you need and Authentication.
- Convex: Your app must use
convex1.42.0 or later. - Chatbot ID: On your chatbot’s Installation page, copy the Chatbot ID.
Set up the component
1
Install the package
In your Convex project, run:
2
Register the component
In The component is now available as
convex/convex.config.ts, add the component and pass it the SITEGPT_API_TOKEN environment variable:convex/convex.config.ts
components.sitegpt.3
Set the API token
Store the token on your Convex deployment:The component reads the token only from
SITEGPT_API_TOKEN. Do not put the token in your code.4
Create the client
Create a
SiteGPT client in your convex/ folder:convex/support.ts
defaultChatbotId is optional. Every method also takes a chatbotId argument. Use it to work with more than one chatbot.Ask the chatbot
ask() sends a message to the chatbot and returns the answer in the same call. It must run in a Convex action.
convex/support.ts
- Without a
threadId,ask()starts a new conversation. - To continue the conversation, pass the
threadIdfrom the last result. - The conversation shows in Chat History like any other conversation. Your team can read it, take it over, and resolve it there.
- If a person on your team has taken over the conversation, the AI does not answer.
answeris thennull. See Conversations and handoff. - If the conversation is resolved,
ask()throws an error with the codeCONVERSATION_CLOSED.
Sync content from a Convex table
CallsyncDocument() in the mutation that saves your data. Call removeDocument() in the mutation that deletes it. Give each document a stable key that you choose, for example articles/pricing.
convex/articles.ts
- The sync request is saved in the same transaction as your own write. If your mutation fails, nothing is sent to SiteGPT.
- After the mutation commits, the component sends the change to SiteGPT in the background. The first sync adds a Markdown file to the chatbot’s content. Later syncs replace the text of that file.
removeDocument()deletes it. - If the content did not change,
syncDocument()sends nothing. You can call it on every save. - If someone deleted the file in the dashboard, the next sync with changed content adds it again.
- A failed sync is tried again after 5 seconds, then after 10, 20, and so on, up to 8 attempts. Then the status is
failed. The nextsyncDocument(),removeDocument(), orretrySync()for that key starts again. - Synced documents use pages of your content quota, like uploaded files. See Plans and limits.
getSyncState()andlistSyncStates()are Convex queries. Your UI can subscribe to them and show the sync status live.
Check that it works
-
Ask a question from your terminal:
The output has an
answerand athreadId. - In the dashboard, open Chat History. The new conversation is in the list.
-
Save one row through your sync mutation. Then run your
syncStatequery. Thestatuschanges frompendingtosynced, anddocumentIdis set. -
In the dashboard, go to Files & Data Sources > Files List. The document is in the list. Its file name comes from the
nameyou gave it, or from thekeyif you gave no name, and ends in.md.
status is failed, read lastError. See Errors.
Reference
Client
If a call has no
chatbotId and the client has no defaultChatbotId, the method throws an error before it sends a request.
Every method takes the Convex ctx first and an arguments object second. Every arguments object also accepts an optional chatbotId. In the tables below, ? marks an optional argument.
Environment variables
To use
SITEGPT_API_BASE, declare it in defineApp with v.optional(v.string()) and pass it in app.use() the same way as the token.
Chat
Runs in an action.answeris the answer text, ornullif the chatbot did not answer.messageis the full message, with the question and the answer.conversationis the new conversation when the call started one. It isnullwhen you passed athreadId.pageUrlmust be a full URL. It is saved with the message.
Content sync
CallsyncDocument, removeDocument, and retrySync in a mutation. Call getSyncState and listSyncStates in a query.
changed is false when the call did not change anything.
A sync state has these fields:
Content
Runs in an action. The arguments match the fields of the API v2 content endpoints. See the API v2 reference.scrapeOptionshas these optional fields:onlyMainContent,includeSelectors,excludeSelectors, andheaders.stateisall,failed,pending, ortrained.deleteDocumentanddeleteDocumentssend the delete confirmation for you. They delete at once.paginationis{ limit, hasNextPage, nextCursor }. PassnextCursorascursorto get the next page.
Conversations and leads
Runs in an action.Account
Runs in an action.
For
getChatbotAnalytics, write startDay and endDay as YYYY-MM-DD dates in UTC. Without a range, the API uses the last 30 days. If analytics is not on your plan, the call fails with 403 and the code ANALYTICS_LOCKED.
The package exports TypeScript types for the return values, for example AskResult, SyncState, SiteGptConversation, and SiteGptLead.
To call a component function without the client, use ctx.runAction() directly. For example: ctx.runAction(components.sitegpt.knowledge.addLinks, { chatbotId: 'YOUR_CHATBOT_ID', urls: ['https://example.com/pricing'] }).
Scopes you need
For content sync, give the token both
knowledge:write and knowledge:delete. The sync deletes the old document when you call removeDocument().
Errors
When the API returns an error, the method throws aConvexError. Its data has these fields:
NON_JSON_RESPONSEandINVALID_API_RESPONSEmean that the answer did not come from API v2. CheckSITEGPT_API_BASE.- If
SITEGPT_API_TOKENis not set, the method throws aConvexErrorthat tells you how to set it. syncDocument()throws in your mutation when thekey,name, orcontentis too long. Your mutation then fails and saves nothing. See Limits.- Errors during the background sync do not reach your mutation. The component saves them in
lastErroron the sync state.