Bill of Lading OCR: Extract Parties, Ports, and Container Numbers
If you searched for bill of lading OCR, you probably have house and master bills arriving as PDFs, phone photos of stamped originals, or agent email attachments, and someone still retypes shipper, consignee, ports, vessel voyage, and container numbers into the forwarding or customs system. Short answer: bill of lading OCR works when you treat the B/L as a reference-heavy layout, not as a simple invoice. Run full-page Markdown OCR so every party block, port pair, and container list is searchable. Use typed JSON only for party names the catalog actually supports. Validate every container number against the ISO 6346 check digit in your own code. Then compare the house bill to the master (and to the commercial invoice) before anything updates a booking or an entry.
This post is about the bill of lading as its own document class: ocean (and multimodal) carriage evidence that names the parties, the route, and the equipment. It is not a full multi-document forwarder walkthrough. For commercial invoices, packing lists, AWBs, and arrival notices in one pipeline, read freight forwarding OCR. For seller invoices as customs and AP evidence, read commercial invoice OCR. For packing-list line reconciliation at receiving, read packing list OCR. For intake folders and a Paperless-ngx archive around BOLs and PODs, use the logistics paperless document workflow.
What a bill of lading actually is
The US International Trade Administration describes a bill of lading as a contract between the owner of the goods and the carrier. For ocean shipments it names two common forms: a straight bill of lading, which is non-negotiable, and a negotiable (shipper’s order) bill of lading, which can be used to buy, sell, or trade the goods while they are in transit. The customer usually needs an original bill of lading as proof of ownership to take possession from the ocean carrier.
In practice, ops desks also live with two layers of documents on the same shipment:
| Document | Who usually issues it | What OCR must not confuse |
|---|---|---|
| Master bill of lading (MBL) | Ocean carrier or NVOCC to the forwarder | Carrier booking, vessel, ports, container list |
| House bill of lading (HBL) | Forwarder to the shipper or consignee | Forwarder references, house parties, often different notify details |
| Sea waybill | Carrier; non-negotiable | Similar fields, but not an order document of title |
| Air waybill | Airline or forwarder (air) | Different number scheme; not a bill of lading |
Classify before you extract. Feeding an HBL into a pipeline that expects an MBL (or an AWB into a B/L folder) creates confident-looking wrong data. The ITA also notes that air waybills are not negotiable documents the way order bills of lading are for vessel shipments, so do not treat AWB OCR as a drop-in replacement for this workflow.
What bill of lading OCR should return
Character recognition is not the hard part. The desk needs a short, trusted set of values:
- Document identity: B/L number, house versus master, issue date if printed
- Parties: shipper, consignee, notify party (and sometimes a delivery agent)
- Route: place of receipt, port of loading, port of discharge, place of delivery
- Conveyance: vessel name, voyage number, and for some forms the flag or call sign
- Cargo summary: number of packages, cargo description, gross weight, measurement
- Equipment: container numbers, size/type codes, seal numbers, sometimes shipper-owned vs carrier-owned flags
- Clauses that matter operationally: freight prepaid or collect, on-board notation, destination control language when present
Most of that lives in labeled blocks and tables that vary by carrier template. A general invoice field catalog will not name bill_of_lading_number, port_of_loading, or container_number for you. Plan on Markdown plus parsers you control.
Two outputs: Markdown for the B/L, typed JSON only where it fits
OCRskill exposes both contracts on the same Bearer-token auth. POST /ocr returns Markdown for any page. POST /ocr.json returns typed JSON for the fields you list. Both accept images (PNG, JPEG, WebP, GIF, BMP, TIFF) and documents including PDF, Word, Excel, and CSV, up to 20 MB per request. A free key from get-key.json is enough to test.
Start with Markdown for every bill of lading:
curl https://api.ocrskill.com/get-key.json
export API_KEY="sk-your-key-here"
curl https://api.ocrskill.com/ocr \
-H "Authorization: Bearer $API_KEY" \
-F "file=@hbl-scan.pdf" > hbl-scan.md
On a clean PDF you typically get labeled party blocks, a route section, and a container or cargo table (sometimes as an HTML <table> inside the Markdown). That file is where B/L numbers, ports, vessel names, seals, and on-board stamps usually live. Keep it next to the original scan so a clerk can search the page without reopening the image.
For parties, the invoice-oriented fields in the documented catalog sometimes map usefully when the layout prints clear shipper and consignee names. seller_name and buyer_name are imperfect synonyms for shipper and consignee, so treat them as hints and verify against the Markdown labels:
curl "https://api.ocrskill.com/ocr.json?fields=seller_name?,buyer_name?" \
-H "Authorization: Bearer $API_KEY" \
-F "file=@hbl-scan.pdf"
An illustrative response shape (values are fictional):
{
"seller_name": "Example Shipper Co., Ltd.",
"buyer_name": "Example Consignee GmbH"
}
Mark both optional with a trailing ? so a stamp that hides one party does not reject the whole request. Dates, when you ask for them on other document types, come back as YYYY-MM-DD. A required field the API cannot find returns 400 with the extracted input_text, so the review queue can show what was read. Unknown field names also return 400. There is no bill_of_lading_number, container_number, port_of_loading, or vessel_name field in the catalog today, so do not invent them in the fields list. Pull those from Markdown instead. The full catalog lives in the OCR JSON API reference, and the structured OCR JSON API post covers required versus optional behavior.
Validate container numbers before they touch the booking
A single misread character on a container ID sends the wrong box to the wrong appointment. ISO 6346 container numbers carry a check digit for exactly that problem. The Bureau International des Containers check digit calculator describes the digit as a way to catch data-entry errors and erroneous OCR readings. The identifier is eleven characters: a three-letter owner code, an equipment category letter (U, J, or Z), a six-digit serial, and the check digit.
This Python sketch scans OCR Markdown for candidate container IDs and flags the ones that fail the check digit:
import re
import sys
# ISO 6346 letter values: A=10 upward, skipping multiples of 11
LETTER_VALUES = {}
value = 10
for ch in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
if value % 11 == 0:
value += 1
LETTER_VALUES[ch] = value
value += 1
CONTAINER_RE = re.compile(r"\b([A-Z]{3}[UJZ])\s?(\d{6})\s?(\d)\b")
def container_ok(owner_cat: str, serial: str, check: str) -> bool:
chars = owner_cat + serial
total = sum(
(LETTER_VALUES[c] if c.isalpha() else int(c)) * (2 ** i)
for i, c in enumerate(chars)
)
return (total % 11) % 10 == int(check)
def find_containers(markdown: str) -> list[dict]:
text = markdown.upper()
return [
{"value": "".join(m.groups()), "valid": container_ok(*m.groups())}
for m in CONTAINER_RE.finditer(text)
]
if __name__ == "__main__":
print(find_containers(open(sys.argv[1], encoding="utf-8").read()))
Run it with python3 find_containers.py hbl-scan.md. On a common test string, CSQU3054383 passes and CSQU3054384 fails. A passing check digit proves the number is well formed, not that it belongs to this booking, so still match it to the carrier or forwarder record. Seal numbers have no universal check digit; compare them to the booking or to the gate-out message when you have one.
Reconcile house versus master, and B/L versus invoice
OCR on a single page is not enough when the shipment file has both an HBL and an MBL:
- Same containers. Container IDs on the house bill should appear on the master (or be a documented subset for groupage). A house container missing from the master is a hard review item.
- Compatible ports. Place of receipt and final delivery can differ between house and master on multimodal moves, but port of loading and port of discharge should not contradict each other without a known transshipment story.
- Party roles. The shipper on the HBL is often the beneficial cargo owner; the shipper on the MBL may be the forwarder. Do not overwrite booking parties from the wrong document layer.
- B/L number hygiene. Keep house and master numbers in separate fields. Never merge them into one “BOL” column.
- Cross-check the commercial invoice. Seller and buyer on the invoice should be consistent with the cargo interest on the house bill, even when the master shows the NVOCC as shipper. Quantity and description fights belong in the same review queue you already use for packing lists.
Wire those checks in code with fuzzy party matching and exact container sets. Anything that fails keeps the original scan one click away.
A practical pipeline for the ops desk
Keep each step small enough that the person who owns the review queue can explain it:
- Capture. Drop agent PDFs, carrier portal downloads, and scanner images into a staging folder keyed by shipment or job number. Keep original bytes and a content hash.
- Classify. Tag HBL, MBL, sea waybill, or “not a B/L” before extraction. Split multipage packets that also contain the invoice or packing list.
- Markdown OCR. Run
/ocron every B/L page and store the Markdown beside the original. - Optional party JSON. Run
/ocr.jsonwith optionalseller_nameandbuyer_nameonly when you want a quick party hint; always verify against Markdown labels. - Validate. Check ISO 6346 container numbers, compare house versus master, and flag missing ports or an empty equipment list.
- Hand off. Push only validated values into the forwarding or customs system, with links back to the scan and Markdown. Who may take delivery, whether an original order bill is required, and what gets filed remain human decisions.
For higher volumes, two paid-key features help. A document URL lets OCRskill fetch a file already in your object storage, and an OCR callback returns 202 and posts the result to your endpoint later. Free keys get 403 for both.
Limitations to plan for before the pilot
Bills of lading look standardized until you stack carrier templates side by side:
- No B/L field catalog. Typed extraction covers common invoice-style parties, not B/L numbers, ports, or equipment. Markdown plus your parsers are the real product.
- Stamps, carbon copies, and fax artifacts. On-board stamps and faded seals raise error rates. Expect more review on those pages.
- Multipage and mixed packets. Agents often staple HBL, MBL, invoice, and packing list into one PDF. Split by document type first.
- House versus master semantics. Party roles differ by design. Blindly mapping
seller_nameinto “shipper” without knowing the document layer creates booking corruption. - Negotiable originals. OCR helps you index and validate data. It does not replace the physical or electronic original when the carrier still requires one for release.
- Compliance stays with people. Extraction helps ops find parties, ports, and container IDs quickly. Carriage terms, release instructions, and customs filings stay with licensed staff and your systems of record.
Measure before you claim accuracy. Take fifty real HBL/MBL pairs from the last quarter across your top lanes, run them through the pipeline, and track how often a clerk still corrects a container ID, port, or party. That number tells you which carriers are ready for light-touch review and which still need a person on every page.
Where OCRskill fits
OCRskill handles the reading step: files in, Markdown or typed JSON out, with a clear 400 when a required field is missing or a field name is unknown. It does not replace your forwarding system, carrier EDI, release workflows, or the judgment behind a booking update. Matching extracted values to jobs, deciding house versus master precedence, and releasing cargo stay in your code and your people.
Conclusion
Bill of lading OCR pays off when you stop treating the page like a domestic invoice. Make every HBL and MBL searchable with Markdown, take only honest party hints from typed JSON, validate container numbers with the ISO 6346 check digit, and reconcile house versus master before the booking changes. Cross-check the commercial invoice so party and cargo fights surface early. Start with one trade lane and one carrier family, measure correction rates, and widen only when the review queue is quiet enough to staff.
To try it, get a key from get-key.json, run a recent house bill through /ocr, optionally through /ocr.json for party hints, and feed the Markdown into the container checker above. Product details and pricing are at ocrskill.com.
