Add citations to your LLM responses

Make your LLM cite its sources with ODEN: every answer comes with ranked, attributable citations, so you can show users where each claim came from.

Use case2 min readUpdated 2026-07-30

An LLM that cannot show its sources is hard to trust and impossible to fact-check. ODEN returns ranked citations with every answer, so your application can attribute each claim to a real URL — the single biggest credibility upgrade you can give an AI feature.

What you get#

Every /search response includes a citations array, ranked by relevance:

{
  "results": {
    "answer": "...",
    "citations": [
      { "title": "Standard Contractual Clauses — European Commission", "url": "https://commission.europa.eu/...", "score": 0.938, "snippet": "The SCCs are model clauses adopted by the Commission..." }
    ]
  }
}

Set include_snippets: true to get one attributed sentence per source — enough to show why a source was cited without fetching the page.

Rendering inline citations#

The clean pattern: number the sources, ask your model to cite [n] inline, and render the numbers as links.

def cited_answer(question: str) -> dict:
    r = requests.post(
        "https://api.oden-api.com/search",
        headers={"Authorization": f"Bearer {os.environ['ODEN_KEY']}"},
        json={"query": question, "include_snippets": True},
        timeout=30,
    ).json()["results"]

    sources = r["citations"]
    numbered = "\n".join(f"[{i+1}] {c['title']} — {c['url']}" for i, c in enumerate(sources))
    prompt = (
        "Answer the question using only these sources and cite them inline as [n].\n\n"
        f"{numbered}\n\nQuestion: {question}"
    )
    # ... send prompt to your model ...
    return {"sources": sources}  # render [n] as links to sources[n-1]["url"]

In the UI, turn each [n] into a link or a hover card pointing at sources[n-1].url. Because ODEN ranks by score, you can also drop weak sources (below ~0.6) before showing them.

Citation deduplication and thresholding pipeline#

To ensure clean user-facing outputs, filter weak relevance scores and deduplicate sources originating from the same root domain:

from urllib.parse import urlparse

def filter_citations(citations: list, min_score=0.65, max_per_domain=2) -> list:
    cleaned = []
    domain_counts = {}

    # Sort descending by relevance confidence score
    for c in sorted(citations, key=lambda x: x.get("score", 0), reverse=True):
        if c.get("score", 0) < min_score:
            continue

        domain = urlparse(c["url"]).netloc
        if domain_counts.get(domain, 0) >= max_per_domain:
            continue

        domain_counts[domain] = domain_counts.get(domain, 0) + 1
        cleaned.append(c)

    return cleaned

Frontend UI hover card rendering#

When building web applications, transform numeric citation tokens [n] into accessible interactive anchors:

// Example React component rendering inline citation tooltips
function CitationBadge({ index, citation }) {
  return (
    <a
      href={citation.url}
      target="_blank"
      rel="noopener noreferrer"
      className="citation-chip"
      title={`${citation.title} (Relevance: ${(citation.score * 100).toFixed(0)}%)`}
    >
      [{index}]
    </a>
  );
}

Why ODEN's citations are trustworthy#

ODEN returns citations as metadata — title, URL, score, and an optional attributed sentence — rather than reproducing full source text. That keeps you on the right side of the TDM opt-out while still giving users a real link to verify against.

FAQ#

Can I get citations without a synthesized answer?#

Yes. Send "answer": false and ODEN returns ranked citations only. See answers and citations.

How do I avoid citing weak sources?#

Filter on score. Dropping citations below about 0.6 removes most low-relevance sources before they reach the user.

Does ODEN guarantee the answer only uses the cited sources?#

ODEN synthesizes from the sources it retrieved and returns them as citations. If you need strict grounding, pass answer: false, take the citations, and do the synthesis yourself with an instruction to use only those sources.

Build it on the free tier
1,000 searches a month, no card required.