Your RAG app cited page 47 -- but the doc only has 30 pages. Verify every citation. Show the source. Flag what's fabricated.
Documentation Β· Get API Key Β· Examples Β· Agent Integration Β· Terms Β· Privacy
const { verifications } = await deepcitation.verify({ llmOutput: response });
// verifications[key].status === "found" --> AI told the truth
// verifications[key].status === "not_found" --> hallucination caughtUpload a PDF. Ask your LLM a question. Get back deterministic, visual proof of what's real and what's fabricated -- for every single citation.
Proof, not detection. Unlike hallucination detectors that flag problems after the fact, DeepCitation verifies each citation against your sources -- with visual proof you can show to users.
| Variant | Style | Best for |
|---|---|---|
linter |
Inline underlines (like a spell-checker) | Long-form content, research tools |
chip |
Pill badges | Chat interfaces |
brackets |
[text] with status |
Technical/academic |
text |
Plain text with indicator | Minimal UI |
superscript |
Footnote style ΒΉ |
Articles, reports |
badge |
Source chip with favicon | ChatGPT-style source attribution |
We're looking for design partners to showcase and help shape the future of citation verification.
Become a design partner β Get early access, direct support, and influence the roadmap.
npm install @deepcitation/deepcitation-jsWorks with any LLM -- OpenAI, Anthropic, Google, Mistral, local models, or any provider that returns text.
| Feature | API key needed? |
|---|---|
| Citation extraction from LLM output | No -- fully local |
| Markdown/Slack/GitHub/HTML/Terminal rendering | No -- fully local |
| Prompt wrapping utilities | No -- fully local |
| React display components | No -- fully local |
| Source document upload & processing | Yes |
| Citation verification against sources | Yes |
| Visual proof image generation | Yes |
import { DeepCitation, wrapCitationPrompt } from "@deepcitation/deepcitation-js";
import { CitationComponent } from "@deepcitation/deepcitation-js/react";
// 1. Upload sources
const dc = new DeepCitation({ apiKey: process.env.DEEPCITATION_API_KEY });
const { deepTextPromptPortion } = await dc.prepareFiles([
{ file: pdfBuffer, filename: "report.pdf" }
]);
// 2. Wrap prompts & call your LLM
const { enhancedSystemPrompt, enhancedUserPrompt } = wrapCitationPrompt({
systemPrompt: "You are a helpful assistant...",
userPrompt: "Summarize the key findings",
deepTextPromptPortion,
});
const response = await yourLLM.chat({ system: enhancedSystemPrompt, user: enhancedUserPrompt });
// 3. Verify -- returns an object (not an array!) keyed by citation hash
const { verifications } = await dc.verify({ llmOutput: response.content });
// 4. Render
<CitationComponent citation={citation} verification={verifications[citationKey]} />Heads up:
verificationsis aRecord<string, Verification>object, not an array. UseObject.keys(verifications).lengthto count results, not.length.
Clone a working example and have citations running in under 2 minutes:
# Next.js chat app with streaming citations
git clone https://github.com/DeepCitation/deepcitation-js.git
cd deepcitation-js/examples/nextjs-ai-sdk
cp .env.example .env.local # add your API keys
npm install && npm run devSee all examples: basic-verification, nextjs-ai-sdk, url-example
PDF, DOCX, XLSX, PPTX, HTML, Images (JPG, PNG, TIFF, WebP, HEIC), URLs
npm install @deepcitation/deepcitation-js react react-dom @radix-ui/react-popoverStyling: Requires Tailwind CSS, or import the bundled stylesheet:
import "@deepcitation/deepcitation-js/styles.css";
| Component | Description |
|---|---|
CitationComponent |
Inline citations with 6 variants and verification popovers |
UrlCitationComponent |
URL citations with favicon and status badges |
CitationDrawer |
ChatGPT-style bottom sheet grouping citations by source |
SourcesListComponent |
Aggregated sources panel with stacked favicons |
For custom layouts, composable primitives are available. API may change:
import { Citation } from "@deepcitation/deepcitation-js/react";
<Citation.Root citation={citation} verification={verification}>
<Citation.Trigger>
<Citation.AnchorText />
<Citation.Indicator />
</Citation.Trigger>
</Citation.Root>Render citations anywhere -- no React required:
import { renderCitationsForSlack } from "@deepcitation/deepcitation-js/slack";
import { renderCitationsForGitHub } from "@deepcitation/deepcitation-js/github";
import { renderCitationsAsHtml } from "@deepcitation/deepcitation-js/html";
import { renderCitationsForTerminal } from "@deepcitation/deepcitation-js/terminal";| Requirement | Version |
|---|---|
| Node.js | >= 18 |
| React (optional, for components) | >= 17 |
@radix-ui/react-popover (optional, for popovers) |
>= 1.0 |
Tailwind CSS (optional, or use styles.css) |
>= 3 |
| Browser target | ES2020+ |
| Problem | Fix |
|---|---|
Error: API key is required |
Set DEEPCITATION_API_KEY env var or pass apiKey to constructor |
Cannot find module '@radix-ui/react-popover' |
Install it: npm install @radix-ui/react-popover (only needed for React components) |
| Citations not showing underlines/colors | Import @deepcitation/deepcitation-js/styles.css or configure Tailwind |
getAllCitationsFromLlmOutput returns {} |
Check that your LLM output contains <cite ... /> tags or deferred JSON blocks -- use wrapCitationPrompt to add citation instructions |
Object.keys(verifications).length is 0 |
Ensure the attachment was uploaded before the LLM call, and the LLM output contains citation references |
import {
AuthenticationError,
RateLimitError,
NetworkError,
ValidationError,
ServerError,
} from "@deepcitation/deepcitation-js";
try {
const { verifications } = await dc.verify({ llmOutput: response.content });
} catch (err) {
if (err instanceof AuthenticationError) {
// Invalid or missing API key
console.error("Check your DEEPCITATION_API_KEY");
} else if (err instanceof RateLimitError) {
// Hit rate limit -- safe to retry after delay
if (err.isRetryable) {
await new Promise(r => setTimeout(r, 1000)); // Implement exponential backoff
// retry verify()
}
} else if (err instanceof NetworkError) {
// Network timeout or temporary failure
if (err.isRetryable) {
// Safe to retry
}
} else if (err instanceof ValidationError) {
// Bad request (invalid citations, file format, etc.)
console.error("Check your input format");
} else if (err instanceof ServerError) {
// Server error (5xx)
if (err.isRetryable) {
// Safe to retry
}
}
// See docs/error-handling.md for full error reference
}Connect to Datadog, Sentry, CloudWatch, OpenTelemetry, or any logging service via an optional logger interface:
const dc = new DeepCitation({
apiKey: process.env.DEEPCITATION_API_KEY,
logger: {
debug: (msg, data) => console.debug(msg, data),
info: (msg, data) => console.info(msg, data),
warn: (msg, data) => console.warn(msg, data),
error: (msg, data) => console.error(msg, data),
},
});
// Or connect to your monitoring service:
// logger: {
// info: (msg, data) => datadog.log('info', msg, data),
// error: (msg, data) => sentry.captureException(new Error(msg), data),
// }The logger receives events for: file uploads, verification requests, cache hits/misses, and errors. Default is a no-op logger.
- Full Documentation
- Examples -- Basic verification, Next.js chat app, URL citations
- Integration Guide -- For AI coding assistants
- Error Handling Guide -- Production error patterns
- Styling Guide -- CSS custom properties and theming
We're looking for design partners to help shape the future of citation verification:
- π€ Become a Design Partner -- Get early access to features, direct support, and influence the roadmap
- π Report an Issue -- Found a bug or have a feature request? We'd love to hear from you
- π¬ Join Discussions -- Connect with other developers building with DeepCitation
Hosted API/service is subject to Terms and Privacy Policy. Patent pending. "DeepCitation" is a trademark.
