ai-answer-citations
Pull the cited sources out of an AI answer.
ChatGPT, Perplexity, Claude and Google AI Overviews all attach sources to the
answers they write, but they attach them differently: an HTML anchor with a
site-name chip, a numbered marker like [3] that links out, a Markdown link in
a copied answer, a footnote definition at the bottom, or a bare URL in plain
text. Anyone measuring which pages AI answers cite has to read all of those
forms before counting anything. This crate reads them.
use ;
let answer = r#"<p>Boil the kettle first.<a href="https://example.com/tea?utm_source=chatgpt.com">[1]</a>
Also see [the guide](https://guide.example.org/tea) and https://example.com/tea.</p>"#;
let cites = extract;
assert_eq!;
assert_eq!;
assert!;
assert_eq!;
let counts = tally;
assert_eq!;
assert_eq!;
What it does
extract(text)returns every absolutehttp(s)link in document order, tagged with the form it was found in (HtmlAnchor,MarkdownLink,Footnote,BareUrl), its visible label, and the numeric marker when the label is one (1,[1],[^1],(1)). A URL inside an anchor or Markdown link is reported once, in the richer form.canonical(url)lower-cases scheme and host, drops a default port and the fragment, and removes click-tracking query keys (utm_*,fbclid,gclid,srsltid, ...) so two citations of one page compare equal. Path case, the remaining query, and the trailing slash are kept: on a real server those can name different pages.host(url)gives the lower-cased host without port, userinfo or a leadingwww..chatgpt_tagged(url)reports theutm_source=chatgpt.comtag ChatGPT appends to the links it cites.tally(&citations)counts citations per host;distinct_pages(&citations)lists canonical URLs in first-seen order.
What it does not do
It does not fetch anything, resolve relative links (an answer copied out of a
chat has no base URL, and a relative link in one is almost never a citation),
or carry a public-suffix list. It is not an HTML parser: it reads <a> tags
and Markdown link syntax out of whatever string you hand it, which is what an
exported answer is.
No dependencies, no unsafe.
Where it comes from
Written as the measurement side of Seen in AI Answers, a page engine built around the question of what AI answers cite. The engine shapes pages to be cited; this crate reads what an answer actually cited, so the two can be compared once a citation sample exists.
License
MIT OR Apache-2.0