DEV Community

Cover image for I built a client-side trade document validator — no upload, no server, just the browser
Tae Kim
Tae Kim

Posted on • Originally published at compare-lab.xyz

I built a client-side trade document validator — no upload, no server, just the browser

The problem I kept hitting: an international invoice with a line total that's off by a cent, or an HS code that appears in the commercial invoice but is absent from the packing list. Customs holds are rarely dramatic. They're usually paperwork.

I wanted a tool that would catch these before the documents left the company. The constraint I set: nothing uploaded to a server. Every byte stays in the browser.

What it does

Upload an invoice and a packing list (Excel or PDF). The tool flags:

  • Sum mismatches — line where qty × unit_price ≠ line total; grand total ≠ sum of lines
  • HS code conflicts — codes present in one document but not the other
  • Quantity discrepancies — total quantities that don't match across documents

The parsing challenge

PDF trade documents are the worst case. They're not structured data. The text extraction gives you a stream of strings with no inherent table structure.

The approach I landed on: extract all text, pattern-match for trailing numeric triples (qty, unit price, line total as the last three numbers on a line), and separately extract HS codes using the \d{4}[\.\-]?\d{2}[\.\-]?\d{0,4} pattern. It's imperfect — complex PDFs with merged cells or rotated text break it — but it catches the common case.

Excel is cleaner. SheetJS gives you a proper row/column grid. The trickier part is header detection: the column labeled "HS" in one document might be "Tariff Code" in another. I match a set of synonyms against lowercased, whitespace-stripped header strings.

Stack

  • Next.js 14, static export, deployed on Cloudflare Workers
  • xlsx for Excel/CSV
  • pdfjs-dist with CDN worker (no bundling headache)
  • All validation logic runs in the browser — parseDocument(), validateSums(), crossValidate()

Free tier

Three document sets per month tracked in localStorage (monthly reset). Paid unlocks unlimited checks and the CSV report download.

Live at: https://compare-lab.xyz/trade-doc-validator/

The source for the validation logic is what I'd most want feedback on. If you deal with trade documents regularly and there's a class of errors this misses, I want to know about it.

Top comments (0)