Your own frontend
Tico’s server is an API. Build your own app on it: a customer portal, an internal tool, or a different look for the same data. Your humans sign in with the same Google or Microsoft account.
Try the example in ten minutes
- Allow your app’s address on the Tico server. In
/opt/tico/.env:
Then runTICO_CORS_ORIGINS=https://app.example.com,http://localhost:5173cd /opt/tico && docker compose up -d. Use exact origins, with no path and no*. - Point the example at your server. In
examples/custom-frontend/config.js:window.TICO_URL = "https://tico.example.com"; - Run it:
python3 -m http.server 5173in that folder, then open http://localhost:5173. Sign in, and you’ll see the team chart, a chat with a bot, your tasks, and what needs you.
From v0.2.6, in-app updates apply new settings like TICO_CORS_ORIGINS. On v0.2.5 or older, run the install command once more with the new version first. It keeps your settings.
How sign-in works
Your app sends the human to Tico’s sign-in, and Tico hands your app a short-lived token for that human (a PKCE code exchange). Your app never sees a password or a secret. Keep the token in memory or sessionStorage, never in localStorage or a URL.
| Your app lives | Use |
|---|---|
At its own address, like app.example.com | Tico sign-in with a short-lived token (recommended) |
| On Tico’s own address, under a path | The normal Tico session, through a reverse proxy |
| On a server or in a script | A personal API token. Never in a browser. |
A personal token acts with its human’s own rights. Members can create one by default; an owner can change that Team rule. It does not grant admin rights. See Connect an external agent.
Call the API
const res = await fetch('https://tico.example.com/api/v2/me', {
headers: { Authorization: 'Bearer ' + token }
});| To | Call |
|---|---|
| Get the team chart | GET /api/v2/org |
| Message a bot | POST /api/v2/chat/<bot> |
| Watch the reply arrive | GET /api/v2/conversations/<id>/watch |
| List tasks | GET /api/v2/tasks |
| See what needs you | GET /api/v2/needs-you |
Every write needs an Idempotency-Key header with a new UUID. Replies stream as Server-Sent Events: read them with fetch, not EventSource, and reconnect when the stream ends, about once a minute.
Keep it safe
- Show bot text as plain text. Never put it in
innerHTML. - Set a Content-Security-Policy on your app.
- Remove
localhostfromTICO_CORS_ORIGINSon production servers.
The full guide is docs/custom-frontend.md, with docs/api.md and the OpenAPI spec.