By team
SDS Extraction for Distributors and Importers
You receive SDS from many suppliers, in many languages, and keep passing them on. Here is how to turn that stream into data.
Last updated: 2026-10-24
Why this team has a particular SDS problem
Under REACH, suppliers of hazardous substances and mixtures, which includes distributors and importers, must provide a safety data sheet to their customers, and must update it when new information becomes available. That puts you in the middle: you receive SDS from many upstream suppliers in different layouts and languages, and you are expected to keep your own records and your customers' copies current. National rules differ, so check with the competent authority.
Four jobs the data can do
| Job | What you read | How it helps |
|---|---|---|
| Onboard a supplier's products | product_identification, composition (CAS numbers) | Create or match product and substance records without re-typing. |
| Notice when an SDS changes | revision_metadata, hazards_identification (H statements) | Compare a new revision with the stored one and flag changed hazards. |
| Flag dangerous goods | transport_information | Mark products with a UN number so logistics sees them; see UN number extraction. |
| Handle documents in other languages | All sections | Keep one schema for every supplier language; see multilingual extraction. |
Notice what changed between revisions
When a supplier sends a new SDS, extract it and compare it with the record you already hold. This function reports new or removed H statements and a changed UN number, from two outputs.json records:
def compare_revisions(old, new):
"""Compare two outputs.json records for the same product and report what changed."""
def h_codes(record):
statements = (record.get("hazards_identification") or {}).get("h_statements") or []
return {str(s).split()[0] for s in statements if s}
def un(record):
return (record.get("transport_information") or {}).get("un_number")
changes = []
added, removed = h_codes(new) - h_codes(old), h_codes(old) - h_codes(new)
if added:
changes.append(f"new hazard statements: {sorted(added)}")
if removed:
changes.append(f"removed hazard statements: {sorted(removed)}")
if un(old) != un(new):
changes.append(f"UN number changed: {un(old)} -> {un(new)}")
return changes
It only reads fields that appear in our sample response, so check what your own documents return. A reported change is a prompt for a person to read both documents, not a finding on its own.
A practical intake flow
- Receive the supplier's SDS PDF and store it with your own record.
- Extract it, using bulk jobs for a backlog and the single-document call for day-to-day intake.
- Match the CAS numbers and product name to existing records, and create new ones where nothing matches.
- If a prior revision exists, run the comparison and route any change to a reviewer.
- Route documents with warnings or low confidence to review before the data feeds anything customer-facing.
This is a data tool, not a compliance decision. Do not use extracted values for storage segregation, labelling or transport decisions without checking them against the source document.
How you get access: the free sample upload on the homepage needs no key, the self-serve plan issues an API key after signup, and enterprise customers get a dedicated deployment with its own base URL. See pricing.
FAQ
Can it tell me when a supplier's SDS has changed?
It extracts each document. Comparing two extractions, as in the function above, is how you find changes. The revision_metadata section carries the revision date when the document has one.
Does it work with SDS in the supplier's own language?
It reads PDFs in the language they are written in and returns the same field names. We do not publish per-language accuracy, so test your suppliers' documents.
Can I process a large backlog?
Yes, in bulk jobs of up to 10 files each, with an idempotency key so a restart does not duplicate work. Limits depend on your plan.