CAS Common Chemistry¶
CAS Common Chemistry is a free subset of CAS REGISTRY: about 500,000
substances with their CAS numbers, names, structures and some experimental
properties. CASCommonChem is a client for its API.
It needs a free API key, which you request from CAS at https://www.cas.org/services/commonchemistry-api. Store it once and every later session finds it:
from provesid.config import set_cas_api_key
set_cas_api_key("your-key")
CASCommonChem(api_key=...), the CCC_API_KEY and CAS_API_KEY environment
variables and a key file are also accepted. A stored key takes precedence over
the environment. API keys has the details.
The outputs below were produced on 2026-09-23.
from provesid import CASCommonChem
ccc = CASCommonChem() # raises ValueError, saying where to put a key, if none is found
By CAS number¶
formaldehyde = ccc.cas_to_detail("50-00-0")
{key: formaldehyde[key] for key in ("status", "found", "rn", "name",
"molecularFormula", "molecularMass",
"canonicalSmile", "inchiKey")}
{'status': 'Success',
'found': True,
'rn': '50-00-0',
'name': 'Formaldehyde',
'molecularFormula': 'CH<sub>2</sub>O',
'molecularMass': '30.03',
'canonicalSmile': 'O=C',
'inchiKey': 'InChIKey=WSFSSNUMVMOOMR-UHFFFAOYSA-N'}
Every method returns a dict with the same keys. status and found say what
happened, and the rest is CAS's record, as CAS writes it: the formula carries
HTML markup (CH<sub>2</sub>O), the InChIKey keeps its InChIKey= prefix,
and the SMILES is in canonicalSmile (smile is empty):
sorted(formaldehyde)
['canonicalSmile', 'cas_rn', 'experimentalProperties', 'found', 'hasMolfile', 'images', 'inchi', 'inchiKey', 'molecularFormula', 'molecularMass', 'name', 'propertyCitations', 'replacedRns', 'rn', 'smile', 'status', 'synonyms', 'uri']
formaldehyde["synonyms"][:10]
['Formaldehyde', 'BFV', 'Fannoform', 'Formalin', 'Formalith', 'Formic aldehyde', 'Formol', 'Fyde', 'Methanal', 'Methyl aldehyde']
experimentalProperties holds what CAS lists, each with a citation number
into propertyCitations:
for prop in formaldehyde["experimentalProperties"]:
print(f"{prop['name']:<20} {prop['property']}")
Boiling Point -19.5 °C Melting Point -92 °C Density 0.8 g/cm³
A CAS number that CAS has retired and merged into another comes back as the
current record. The old number is listed in replacedRns:
formaldehyde["replacedRns"][:5]
['8005-38-7', '8006-07-3', '8013-13-6', '112068-71-0', '1053659-79-2']
By name and by SMILES¶
name_to_detail makes two requests: a search, then the record of the first
hit. When the search finds several, a warning is logged and the others are
ignored, so check name against what you asked for.
A name is found only if CAS lists it as a synonym. "acetone" is, and "propan-2-one" is not:
for name in ["caffeine", "acetone", "propan-2-one"]:
record = ccc.name_to_detail(name)
print(f"{name:<14} -> {record['status']:<10} {record['rn']:<10} {record['name']}")
caffeine -> Success 58-08-2 Caffeine acetone -> Success 67-64-1 Acetone
propan-2-one -> Not found
for smiles in ["CCO", "OCC", "C1=CC=CC=C1", "C=O", "[Na+].[Cl-]"]:
record = ccc.smiles_to_detail(smiles)
print(f"{smiles:<12} -> {record['status']:<8} {record['rn']:<10} {record['name']}")
CCO -> Success 64-17-5 Ethanol OCC -> Success 64-17-5 Ethanol C1=CC=CC=C1 -> Success 71-43-2 Benzene C=O -> Success 50-00-0 Formaldehyde [Na+].[Cl-] -> Success 7647-14-5 Sodium chloride
smiles_to_detail does not send the SMILES. CAS's search matches a SMILES
only as the exact string CAS stores, so CCO would find nothing. It sends the
standard InChI that RDKit writes, which CAS matches however the SMILES is
spelled. It then keeps the record that is the substance itself. CAS gives
dimers and polymers the InChI of their repeat unit, so formaldehyde's InChI
also finds paraformaldehyde, and sodium chloride's also finds rock salt. The
method keeps records whose formula matches the SMILES, and of those takes the
one with the most synonyms; the others are named in a logged warning. Each
hit costs one request the first time it is seen (water's InChI has 30 hits),
and the answers are cached.
Absence and failure¶
Nothing raises. status separates the two cases that matter: CAS answered
and has no such substance, or CAS could not be asked at all.
status |
Meaning |
|---|---|
Success |
CAS answered; found is True |
Not Found / Not found |
CAS answered, and there is no such substance |
Unauthorized - Check API Key |
the key was rejected; fix the key |
Timeout / Network Error |
CAS could not be reached; try again later |
Invalid Request |
CAS rejected the request itself |
Invalid SMILES |
RDKit could not read the SMILES; nothing was sent |
for label, record in [
("invalid CAS number", ccc.cas_to_detail("0000-00-0")),
("unknown name", ccc.name_to_detail("thiscompounddoesnotexist12345")),
("unparseable SMILES", ccc.smiles_to_detail("not-a-smiles")),
]:
print(f"{label:<20} status={record['status']!r:<17} found={record['found']}")
CAS lookup failed for CAS RN 0000-00-0: No data for https://commonchemistry.cas.org/api/detail?cas_rn=0000-00-0 (HTTP 404)
invalid CAS number status='Not Found' found=False unknown name status='Not found' found=False unparseable SMILES status='Invalid SMILES' found=False
import pandas as pd
rows = []
for cas in ["64-17-5", "67-56-1", "78-93-3", "71-43-2"]:
record = ccc.cas_to_detail(cas)
if record["found"]:
rows.append({key: record[key] for key in
("rn", "name", "molecularFormula", "molecularMass", "inchiKey")})
pd.DataFrame(rows)
| rn | name | molecularFormula | molecularMass | inchiKey | |
|---|---|---|---|---|---|
| 0 | 64-17-5 | Ethanol | C<sub>2</sub>H<sub>6</sub>O | 46.07 | InChIKey=LFQSCWFLJHTTHZ-UHFFFAOYSA-N |
| 1 | 67-56-1 | Methanol | CH<sub>4</sub>O | 32.04 | InChIKey=OKKJLVBELUTLKV-UHFFFAOYSA-N |
| 2 | 78-93-3 | Methyl ethyl ketone | C<sub>4</sub>H<sub>8</sub>O | 72.11 | InChIKey=ZWEHNKRNPOVVGH-UHFFFAOYSA-N |
| 3 | 71-43-2 | Benzene | C<sub>6</sub>H<sub>6</sub> | 78.11 | InChIKey=UHOVQNZJYSORNB-UHFFFAOYSA-N |
For more than a handful of CAS numbers, Search("cas") answers from the
offline databases without a key or a network connection. See the
Search tutorial.