# How to add citations to an AI chatbot

> A practical guide to source-cited AI answers: what claim-level citations are, why retrieval alone is not enough, and how to ship highlighted PDF evidence with the Uthereal Cortex SDK.

- Canonical page: https://uthereal.ai/developers/rag-with-citations
- Last updated: 2026-09-18
- Product: Uthereal Cortex (sovereign enterprise AI, Swiss/EU data residency)
- npm package: `@uthereal-sdk/cortex` (https://www.npmjs.com/package/@uthereal-sdk/cortex)
- Repository: https://github.com/Uthereal-Labs/Uthereal-Cortex-SDK

## Short answer

Short answer: retrieve passages with stable identifiers, keep those identifiers attached through generation, and map each claim in the answer back to the passage that supports it - never let the model write citation text itself. The Uthereal Cortex SDK does this end to end, including PDF pages opened at the highlighted passage.

Users trust an AI answer when they can check it. This guide covers the architecture behind source-cited answers - and the shortcut that skips building it.

## Why most chatbot citations cannot be trusted

- The model is asked to produce citation markers as text, so it can invent them
- Citations point at whole documents, leaving the reader to search manually
- Chunks lose page and position data during ingestion, so nothing can be highlighted
- Retrieval returns similar text, not the text that actually supported the claim

Each of these fails the same test: a reader cannot verify a single sentence in under five seconds. In regulated, medical, legal, financial or publishing work, that failure makes the whole feature unusable.

## The architecture that works

Five layers, in order. Skipping any of them is where citation quality breaks.

- Layout-aware parsing - keep headings, tables, page numbers and character spans
- Semantic chunking - coherent passages with stable identifiers, not fixed-size cuts
- Retrieval and reranking - recall first, then precision on the shortlist
- Grounded generation - the model answers only from the retrieved passages
- Claim resolution - each claim is mapped back to the passage identifiers that support it

> The identifiers are the whole trick. Once a passage identifier survives from ingestion to the rendered answer, a citation becomes a lookup instead of a guess.

## Shipping it with the Uthereal Cortex SDK

Cortex exposes the pipeline as two calls: ask for a cited answer, rag for ranked evidence.

```
// server - your authenticated endpoint
import { createCortexHandler } from "@uthereal-sdk/cortex/server";

export const handler = createCortexHandler({
  config: {
    baseUrl: process.env.CORTEX_API_BASE_URL!,
    assistantId: process.env.CORTEX_ASSISTANT_ID!,
    apiKey: process.env.CORTEX_SHARED_API_KEY!, // server secret only
  },
  allowedOrigin: "https://your-app.example",
  authenticate: async (request) => verifyYourApplicationSession(request),
  store: yourStoreAdapter,
});
```
_One authenticated endpoint_

```
// browser - stream the answer, render clickable citations
import { createCortexBrowserClient } from "@uthereal-sdk/cortex/browser";
import { CitedAnswer } from "@uthereal-sdk/cortex/react";

const cortex = createCortexBrowserClient({ endpoint: "/cortex", fetch: authedFetch });
// Render inside a QueryClientProvider; create one if the app has none.
const id = await cortex.createConversation();
for await (const update of cortex.ask(id, { message })) render(update);

<CitedAnswer key={[backendId, tenantId, accountId].join(":")} answer={saved.answer}
  messageId={saved.id} authScope={[backendId, tenantId, accountId].join(":")}
  loadPdf={cortex.pdf} />;
```
_Citations render themselves_

Clicking a citation calls cortex.pdf, which returns the source page with the supporting passage highlighted - no viewer to build.

## Ship checklist

- Every claim resolves to a passage a reader can open
- The answer refuses rather than guesses when retrieval finds nothing
- The API key never reaches the browser bundle
- Sessions and users map to your own authenticated records, not client input
- Retrieval-only output (rag) is available for workflows that need raw evidence

## Frequently asked questions

### What is a claim-level citation?

A citation attached to a single assertion inside the answer rather than to the answer as a whole. The reader can check each statement against the passage it came from, instead of being handed a list of documents and told to look.

### Why do chatbots cite the wrong source?

Most implementations ask the model to invent citation markers from retrieved text. The model can fabricate or misattribute them. Citations must be resolved from the retrieval layer - the passage identifiers that actually fed the answer - not generated as text.

### How do PDF citations open the right page?

Each retrieved passage keeps its document, page and character span. The citation resolves to a signed reference token, and the PDF viewer opens that page with the passage highlighted.

### Is a vector database enough for citations?

No. A vector store gives you similar chunks. Trustworthy citations also need layout-aware parsing, stable passage identifiers, reranking, claim-to-passage mapping, and a viewer that can highlight the original. That pipeline is what Cortex provides.

### Does grounding improve accuracy?

It improves verifiable accuracy, which is the part that matters in regulated work. A grounded answer can be checked; an ungrounded one can only be believed.

## Related pages

- [Best RAG API with sources](https://uthereal.ai/developers/rag-api): What to look for when choosing one.
- [Build it yourself vs a RAG SDK](https://uthereal.ai/developers/rag-sdk-comparison): What each option actually costs.
- [Uthereal Cortex SDK](https://uthereal.ai/developers/sdk): Full developer guide.
- [Cursor setup](https://uthereal.ai/developers/cursor): Let your AI tool wire it in.

## Next steps

- Create an agent and a scoped server key: https://agent.uthereal.ai
- Full SDK guide (HTML): https://uthereal.ai/developers/sdk
- Full SDK guide (Markdown): https://uthereal.ai/developers/sdk.md
- AI index for this site: https://uthereal.ai/llms.txt and https://uthereal.ai/llms-full.txt
- Help: sdk@uthereal.ai
