Report JSON cookbook
Rendering highlights from character offsets, walking sources and passages, and handling partial coverage — with working code.
The report from GET /v1/checks/{id}/report is designed for building UIs:
every match carries exact character offsets into the query text, and the
report includes the query text itself so you can render highlights without
keeping your own copy. This page is the recipes; the field-by-field
reference is in the API overview.
The shape you're working with
Two views of the same matches: sources[].passages[] is per-source (who
matched what), unique_passages is the deduplicated union over your text
(what to highlight, and what the score sums).
Recipe: highlight matched text
Offsets are [start, end) character positions into query_text.
unique_passages is merged and non-overlapping, so rendering is a single
pass — walk the text, alternating plain and highlighted slices:
The same in Python, producing HTML:
Escape the text slices (as above) — the submitted document is untrusted input to your UI.
Recipe: which sources matched this passage?
Map each unique passage to the sources whose passages overlap it:
That interval-overlap test is all you need for click-a-passage → show its sources, because per-source passages may cover only part of a merged unique passage.
Recipe: compute your own score
overall_similarity_pct is derived from total_matched_chars (the sum of
unique_passages lengths) over the text length. If you filter matches in
your UI — say, dropping passages under N characters — recompute honestly
from the passages you kept, and label the score as filtered.
Handle partial coverage
Very large documents can hit the per-check time budget. Check coverage:
when it's "partial" (coverage_reason: "time_cap"), every match found is
present, but unchecked chunks remain — checked_chunks / total_chunks
tell you how far it got. Say so in your UI; don't present a partial scan as
a complete one.
Don't diff the preview text
overlap_text_preview is a display string for the source side, not an
offset-stable copy — render it, but never compute positions against it.
Positions always come from query_start / query_end on your own text.