Skip to main content
@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.
The component also has typed methods for content, conversations, leads, and account data. The package is on npm and in the official Convex Components directory.
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 convex 1.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 convex/convex.config.ts, add the component and pass it the SITEGPT_API_TOKEN environment variable:
convex/convex.config.ts
The component is now available as 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 threadId from 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. answer is then null. See Conversations and handoff.
  • If the conversation is resolved, ask() throws an error with the code CONVERSATION_CLOSED.

Sync content from a Convex table

Call syncDocument() 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
How the sync works:
  • 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 next syncDocument(), removeDocument(), or retrySync() for that key starts again.
  • Synced documents use pages of your content quota, like uploaded files. See Plans and limits.
  • getSyncState() and listSyncStates() are Convex queries. Your UI can subscribe to them and show the sync status live.

Check that it works

  1. Ask a question from your terminal:
    The output has an answer and a threadId.
  2. In the dashboard, open Chat History. The new conversation is in the list.
  3. Save one row through your sync mutation. Then run your syncState query. The status changes from pending to synced, and documentId is set.
  4. In the dashboard, go to Files & Data Sources > Files List. The document is in the list. Its file name comes from the name you gave it, or from the key if you gave no name, and ends in .md.
If 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.
  • answer is the answer text, or null if the chatbot did not answer.
  • message is the full message, with the question and the answer.
  • conversation is the new conversation when the call started one. It is null when you passed a threadId.
  • pageUrl must be a full URL. It is saved with the message.

Content sync

Call syncDocument, 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.
  • scrapeOptions has these optional fields: onlyMainContent, includeSelectors, excludeSelectors, and headers.
  • state is all, failed, pending, or trained.
  • deleteDocument and deleteDocuments send the delete confirmation for you. They delete at once.
  • pagination is { limit, hasNextPage, nextCursor }. Pass nextCursor as cursor to 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 a ConvexError. Its data has these fields:
  • NON_JSON_RESPONSE and INVALID_API_RESPONSE mean that the answer did not come from API v2. Check SITEGPT_API_BASE.
  • If SITEGPT_API_TOKEN is not set, the method throws a ConvexError that tells you how to set it.
  • syncDocument() throws in your mutation when the key, name, or content is 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 lastError on the sync state.
For the API error codes, see API conventions.

Limits