
Pubchem Database
- 1.2k installs
- 2.6k repo stars
- Updated July 7, 2026
- google-deepmind/science-skills
pubchem-database is a skill that queries PubChem compound properties, structures, bioassays, and synonyms via PUG-REST and PUG-View APIs for developers who need authoritative chemical identifiers inside agent workflows.
About
pubchem-database is a science skill from google-deepmind/science-skills for querying NCBI PubChem through PUG-REST computed-property search and PUG-View record APIs. It documents URL paths across domains including compound, substance, assay, gene, protein, pathway, taxonomy, and cell, with namespaces for CID, chemical name, SMILES, and InChI identifiers. Developers use pubchem-database when building cheminformatics pipelines, drug-discovery agents, or lab tooling that must fetch structures, synonyms, and bioassay metadata without hand-crafting REST paths. The skill also references a pubchem_api.py wrapper and raw API fallbacks when wrapper coverage is insufficient.
- Full PUG-REST and PUG-View API reference for compound, substance, assay, gene, protein, pathway, taxonomy and cell domai
- Supports exact lookups by CID, name, SMILES, InChIKey, formula plus fast substructure, similarity and identity searches
- Extracts specific properties, synonyms, CIDs, assay summaries, cross-references and full records
- Returns data in JSON, XML, CSV, TXT or PNG formats
- Enables precise chemical data retrieval when the pubchem_api.py wrapper is insufficient
Pubchem Database by the numbers
- 1,186 all-time installs (skills.sh)
- +57 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #261 of 2,064 Data Science & ML skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/google-deepmind/science-skills --skill pubchem-databaseAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.2k |
|---|---|
| repo stars | ★ 2.6k |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 7, 2026 |
| Repository | google-deepmind/science-skills ↗ |
How do you query PubChem compound data programmatically?
Query chemical compound properties, structures, bioassays and synonyms directly from PubChem inside agentic workflows.
Who is it for?
Developers building cheminformatics tools or science agents that need PubChem compound and bioassay data via REST.
Skip if: General web scraping tasks unrelated to chemical databases or projects that only need non-chemical public datasets.
When should I use this skill?
User mentions PubChem, PUG-REST, chemical structures, SMILES lookup, bioassay data, or compound properties.
What you get
Structured PubChem API responses with compound properties, SMILES/InChI structures, bioassay hits, and synonym lists.
- API query results
- compound metadata JSON
Files
PubChem Database
Prerequisites
1. `uv`: Read the uv skill and follow its Setup instructions to ensure uv is installed and on PATH. 2. User Notification: If LICENSE_NOTIFICATION.txt does not already exist in this skill directory then (1) prominently notify the user to check the terms at https://pubchem.ncbi.nlm.nih.gov/docs/citation-guidelines and https://pubchem.ncbi.nlm.nih.gov/docs/pug-rest, then (2) create the file recording the notification text and timestamp.
Quick Start
PubChem queries are executed via a robust Python wrapper script to respect terms-of-service and handle complex JSON parsing. This script allows safe multi-agent use of APIs.
Example: Resolve a chemical name to its Compound ID (CID)
uv run scripts/pubchem_api.py resolve --name "aspirin" --output result.jsonCore Rules
- Use the Wrapper: ALWAYS execute the provided helper scripts to query the
database rather than accessing the database directly. The scripts automatically enforce the required rate limit gracefully.
- Read the generated JSON output file, and process it with jq or code.
- Verify Facts: ALWAYS verify information retrieved from memory with a
database query if the user asks for a specific fact that can be checked in PubChem. Do not rely solely on internal knowledge.
- Notification: If this skill is used, ensure this is mentioned in the
output.
Core Capabilities
1. Compound Resolution (Name or InChI to Identifiers) Convert chemical/trade names or InChI strings into PubChem CIDs, SMILES, and InChIKeys.
uv run scripts/pubchem_api.py resolve --name "ibuprofen" --output result.json
# OR
uv run scripts/pubchem_api.py resolve --inchi "InChI=1S/C3/c1-3-2/i1+1" --output result.json2. Physical & Chemical Property Retrieval Fetch computed properties (e.g., MolecularWeight, XLogP, TPSA).
uv run scripts/pubchem_api.py properties --cid 2244 --output result.json3. Synonyms and Trade Names Find alternative names and brand names.
uv run scripts/pubchem_api.py synonyms --cid 2244 --output result.jsonAdvanced Context
4. Safety and Hazard Information (GHS) Retrieve Global Harmonized System hazard statements and handling precautions (uses PUG-View).
uv run scripts/pubchem_api.py safety --cid 2244 --output result.json5. Drug and Medication Information Fetch FDA pharmacology data, mechanism of action, and therapeutic uses (uses PUG-View).
uv run scripts/pubchem_api.py pharmacology --cid 2244 --output result.json6. Custom Heading (PUG-View) Retrieve any specific heading from the PUG-View system (e.g., 'Geometry', 'Crystal Structures').
uv run scripts/pubchem_api.py view --cid 3939 --heading "Crystal Structures" --output result.json7. Image Generation Retrieve 2D chemical structure images. The script returns a Markdown-formatted image link.
uv run scripts/pubchem_api.py image --cid 2244 --output result.jsonComplex Search & Biology
8. Structure-Based Searching (Similarity & Substructure) Find molecules similar to a SMILES string or containing a specific substructure.
uv run scripts/pubchem_api.py similarity --smiles "CC(=O)OC1=CC=CC=C1C(=O)O" --output result.jsonand
uv run scripts/pubchem_api.py substructure --smiles "C1=CC=CC=C1" --output result.json9. BioAssay & Target Interactions Identify genes or proteins a chemical interacts with.
uv run scripts/pubchem_api.py assays --cid 2244 --output result.jsonAdvanced Usage & Workflows
10. Cross-references (Xrefs) Fetch identifiers cross-referenced with a CID (e.g., PatentID, PubMedID).
uv run scripts/pubchem_api.py xrefs --cid 2244 --type "PatentID" --output result.json11. Property Range Search Find CIDs within a specific property range. Supported features include: molecular_weight, heavy_atom_count, xlogp, tpsa, h_bond_donor_count, h_bond_acceptor_count, rotatable_bond_count, exact_mass, monoisotopic_mass, and complexity.
uv run scripts/pubchem_api.py range --feature molecular_weight --min 400.0 --max 400.05 --output result.json12. Custom PUG-REST Query Execute a raw path against the PUG-REST API.
uv run scripts/pubchem_api.py query --path "compound/cid/2244/xrefs/PatentID/JSON" --output result.jsonFallback Search Strategies
If direct resolution by name or formula fails (e.g., for complex compounds or specific ions):
- Search for parent/neutral molecule: If searching for an ion or salt, try
searching for the neutral parent compound.
- Deconstruct complex formulas: If a complex formula returns no results,
try searching for major components or ligands.
- Use substructure or similarity search: If you have a SMILES string or
can generate one for a component, use it to find related compounds.
Complex Queries and Multi-Step Tasks
- Custom/Complex Queries: For more details, read
references/endpoints.md to construct raw PUG-REST URLs.
- Multi-Step Tasks: For complex tasks like drug discovery pipelines,
follow the checklists in references/workflows.md.
Advanced PubChem API Reference
This file documents the raw PUG-REST and PUG-View APIs for cases where the pubchem_api.py wrapper does not support your specific query.
PUG-REST (Computed Properties & Search)
Base URL: https://pubchem.ncbi.nlm.nih.gov/rest/pug
The URL path always follows this structure: /<domain>/<namespace>/<identifiers>/<operation>/<output>[?options]
1. Domain
The core data type: compound, substance, assay, gene, protein, pathway, taxonomy, cell.
2. Namespace & Identifiers
How you are identifying the target record(s):
cid/<cid>: Compound IDname/<name>: Exact chemical namesmiles/<smiles>: Exact SMILES matchinchikey/<inchikey>: Exact InChIKey matchformula/<formula>: Exact molecular formula- Search namespaces (use
fastprefix for synchronous): fastsubstructure/smiles/<smiles>fastsimilarity_2d/smiles/<smiles>fastidentity/smiles/<smiles>
3. Operation
What data you want to extract:
record(default): The full raw record.property/<property_list>: Specific properties (e.g.,
MolecularWeight,XLogP,TPSA).
synonyms: List of synonyms.cids: Return only the CIDs (useful after a search).assaysummary: Summary of bioassays.xrefs/<xref_type>: Cross-references (e.g.,PatentID,PubMedID).
4. Output
Format for the response: JSON, XML, CSV, TXT, PNG.
Examples
- Properties by CID (JSON):
https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/2244/property/MolecularWeight,MolecularFormula/JSON - Mass Range Search (JSON):
https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/molecular_weight/range/400.0/400.05/cids/JSON - Patents by SID (JSON):
https://pubchem.ncbi.nlm.nih.gov/rest/pug/substance/sid/137349406/xrefs/PatentID/JSON
---
PUG-View (Third-Party Annotations & Text)
Used for retrieving comprehensive textual annotations (like GHS Safety, Pharmacology, Toxicity) compiled from external sources.
Base URL: https://pubchem.ncbi.nlm.nih.gov/rest/pug_view
The standard structure for retrieving specific sections: https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound/<cid>/JSON?heading=<Section+Heading>
Note: Spaces in headings must be replaced with `+`.
Common Headings
-
Safety+and+Hazards -
Pharmacology+and+Biochemistry -
Toxicity -
Drug+and+Medication+Information -
Experimental+Properties
PubChem Workflows
Follow these checklists for complex, multi-step queries to ensure accurate results.
Workflow 1: Comprehensive Chemical Profiling
When asked to provide a complete profile of a chemical (e.g., "Tell me everything about Aspirin"):
1. Resolve Name: Run pubchem_api.py resolve to get the primary CID. 2. Get Properties: Run pubchem_api.py properties using the CID to get basic chemical traits (Weight, XLogP). 3. Check Safety: Run pubchem_api.py safety to fetch GHS hazard information. 4. Check Pharmacology: Run pubchem_api.py pharmacology to understand its biological/medical use. 5. Synthesize: Read all output JSON files and compile a comprehensive markdown report.
Workflow 2: Structure-Based BioAssay Lookup
When asked to find targets or assays for compounds similar to a given structure:
1. Search Structure: Run pubchem_api.py similarity (for 2D similarity) or pubchem_api.py substructure using the target SMILES string. 2. Filter Results: Read the resulting JSON file. The search may return hundreds of CIDs. Select the top 5-10 most relevant CIDs. 3. Fetch Assays: For each selected CID, run pubchem_api.py assays. 4. Analyze: Review the assay summaries to identify common biological targets (e.g., specific genes or proteins) that these compounds interact with.
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""PubChem API CLI.
This script provides command-line access to various PubChem API endpoints,
including resolving chemical names, fetching properties, synonyms, safety data,
pharmacology, images, and performing similarity/substructure searches.
"""
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "scienceskillscommon",
# ]
# [tool.uv.sources]
# scienceskillscommon = { path = "../../scienceskillscommon" }
# ///
import argparse
import json
import sys
import urllib.parse
from science_skills.skills.scienceskillscommon import http_client
PUBCHEM_BASE_URL = "https://pubchem.ncbi.nlm.nih.gov/rest"
_CLIENT = http_client.HttpClient(PUBCHEM_BASE_URL, qps=5)
def make_request(url):
"""Makes an HTTP GET request via http_client."""
try:
resp = _CLIENT.fetch(url)
content_type = resp.headers.get("Content-Type", "")
if "application/json" in content_type:
return resp.json()
elif "text/plain" in content_type or "text/csv" in content_type:
return resp.text
else:
return resp.data
except http_client.HttpError as e:
if e.status_code == 404:
return {"error": "Record not found (HTTP 404)."}
elif e.status_code == 400:
return {"error": "Bad request (HTTP 400). Please check your inputs."}
else:
return {"error": f"HTTP Error {e.status_code or 'Error'}: {e.body}"}
def write_output(data, output_file):
"""Writes output to a JSON file."""
try:
with open(output_file, "w", encoding="utf-8") as f:
if isinstance(data, str):
json.dump({"result": data}, f, indent=2)
else:
json.dump(data, f, indent=2)
print(f"Success! Data written to: {output_file}")
except (OSError, TypeError) as e:
print(f"Error writing to file {output_file}: {e}")
sys.exit(1)
def resolve(name=None, inchi=None):
"""Resolves a chemical name or InChI to CIDs and SMILES."""
if name:
encoded_val = urllib.parse.quote(name)
input_type = "name"
elif inchi:
encoded_val = urllib.parse.quote(inchi)
input_type = "inchi"
else:
return {"error": "Either name or inchi must be provided."}
url_cids = (
f"{PUBCHEM_BASE_URL}/pug/compound/{input_type}/{encoded_val}/cids/JSON"
)
url_props = f"{PUBCHEM_BASE_URL}/pug/compound/{input_type}/{encoded_val}/property/CanonicalSMILES,IsomericSMILES,InChIKey/JSON"
cids_data = make_request(url_cids)
if isinstance(cids_data, dict) and "error" in cids_data:
return cids_data
props_data = make_request(url_props)
return {"identifiers": cids_data, "properties": props_data}
def properties(cid):
url = f"{PUBCHEM_BASE_URL}/pug/compound/cid/{cid}/property/MolecularFormula,MolecularWeight,XLogP,TPSA,ExactMass,HBondDonorCount,HBondAcceptorCount,RotatableBondCount/JSON"
return make_request(url)
def synonyms(cid):
url = f"{PUBCHEM_BASE_URL}/pug/compound/cid/{cid}/synonyms/JSON"
return make_request(url)
def safety(cid):
url = f"{PUBCHEM_BASE_URL}/pug_view/data/compound/{cid}/JSON?heading=Safety+and+Hazards"
return make_request(url)
def pharmacology(cid):
url = f"{PUBCHEM_BASE_URL}/pug_view/data/compound/{cid}/JSON?heading=Pharmacology+and+Biochemistry"
return make_request(url)
def view(cid, heading):
encoded_heading = urllib.parse.quote(heading)
url = f"{PUBCHEM_BASE_URL}/pug_view/data/compound/{cid}/JSON?heading={encoded_heading}"
return make_request(url)
def xrefs(cid, xref_type):
url = f"{PUBCHEM_BASE_URL}/pug/compound/cid/{cid}/xrefs/{xref_type}/JSON"
return make_request(url)
def query(path):
clean_path = path.lstrip("/")
url = f"{PUBCHEM_BASE_URL}/{clean_path}"
return make_request(url)
def image(cid):
url = f"{PUBCHEM_BASE_URL}/pug/compound/cid/{cid}/PNG"
return {"image_url": url, "markdown": f""}
def similarity(smiles):
encoded_smiles = urllib.parse.quote(smiles)
url = f"{PUBCHEM_BASE_URL}/pug/compound/fastsimilarity_2d/smiles/{encoded_smiles}/cids/JSON"
return make_request(url)
def substructure(smiles):
encoded_smiles = urllib.parse.quote(smiles)
url = f"{PUBCHEM_BASE_URL}/pug/compound/fastsubstructure/smiles/{encoded_smiles}/cids/JSON"
return make_request(url)
def assays(cid, active_only=False):
url = f"{PUBCHEM_BASE_URL}/pug/compound/cid/{cid}/assaysummary/JSON"
data = make_request(url)
if active_only:
data = filter_active_assays(data)
return data
def filter_active_assays(data):
if not isinstance(data, dict) or "Table" not in data:
return data
table = data["Table"]
columns = table.get("Columns", {}).get("Column", [])
try:
outcome_idx = columns.index("Activity Outcome")
except ValueError:
return data
filtered_rows = []
for row in table.get("Row", []):
cell = row.get("Cell", [])
if len(cell) > outcome_idx and cell[outcome_idx] == "Active":
filtered_rows.append(row)
table["Row"] = filtered_rows
return data
def range_search(feature, min_val, max_val):
url = f"{PUBCHEM_BASE_URL}/pug/compound/{feature}/range/{min_val}/{max_val}/cids/JSON"
return make_request(url)
def main():
parser = argparse.ArgumentParser(description="PubChem API Wrapper Script")
subparsers = parser.add_subparsers(dest="command", required=True)
# Resolve
p_resolve = subparsers.add_parser(
"resolve", help="Resolve a chemical name or InChI to CIDs and SMILES"
)
group = p_resolve.add_mutually_exclusive_group(required=True)
group.add_argument("--name", help="Chemical name")
group.add_argument("--inchi", help="InChI string")
p_resolve.add_argument(
"--output", required=True, help="Output JSON file path"
)
# Properties
p_props = subparsers.add_parser(
"properties", help="Get chemical properties for a CID"
)
p_props.add_argument("--cid", required=True, help="Compound ID")
p_props.add_argument("--output", required=True, help="Output JSON file path")
# Synonyms
p_syn = subparsers.add_parser("synonyms", help="Get synonyms for a CID")
p_syn.add_argument("--cid", required=True, help="Compound ID")
p_syn.add_argument("--output", required=True, help="Output JSON file path")
# Safety
p_safe = subparsers.add_parser("safety", help="Get GHS safety data for a CID")
p_safe.add_argument("--cid", required=True, help="Compound ID")
p_safe.add_argument("--output", required=True, help="Output JSON file path")
# Pharmacology
p_pharm = subparsers.add_parser(
"pharmacology", help="Get pharmacology data for a CID"
)
p_pharm.add_argument("--cid", required=True, help="Compound ID")
p_pharm.add_argument("--output", required=True, help="Output JSON file path")
# View
p_view = subparsers.add_parser(
"view", help="Get specific PUG-View heading for a CID"
)
p_view.add_argument("--cid", required=True, help="Compound ID")
p_view.add_argument(
"--heading", required=True, help="Heading (e.g. 'Geometry')"
)
p_view.add_argument("--output", required=True, help="Output JSON file path")
# Xrefs
p_xrefs = subparsers.add_parser(
"xrefs", help="Get cross-references (PatentID, PubMedID, etc.) for a CID"
)
p_xrefs.add_argument("--cid", required=True, help="Compound ID")
p_xrefs.add_argument(
"--type", required=True, help="Xref type (e.g. 'PatentID')"
)
p_xrefs.add_argument("--output", required=True, help="Output JSON file path")
# Query
p_query = subparsers.add_parser(
"query", help="Execute a custom PUG-REST path"
)
p_query.add_argument(
"--path",
required=True,
help="e.g., compound/cid/2244/xrefs/PatentID/JSON",
)
p_query.add_argument("--output", required=True, help="Output JSON file path")
# Image
p_img = subparsers.add_parser("image", help="Get image URL for a CID")
p_img.add_argument("--cid", required=True, help="Compound ID")
p_img.add_argument("--output", required=True, help="Output JSON file path")
# Similarity
p_sim = subparsers.add_parser(
"similarity", help="Fast 2D similarity search by SMILES"
)
p_sim.add_argument("--smiles", required=True, help="SMILES string")
p_sim.add_argument("--output", required=True, help="Output JSON file path")
# Substructure
p_sub = subparsers.add_parser(
"substructure", help="Fast substructure search by SMILES"
)
p_sub.add_argument("--smiles", required=True, help="SMILES string")
p_sub.add_argument("--output", required=True, help="Output JSON file path")
# Assays
p_assay = subparsers.add_parser("assays", help="Get assay summary for a CID")
p_assay.add_argument("--cid", required=True, help="Compound ID")
p_assay.add_argument(
"--active-only", action="store_true", help="Filter for active assays only"
)
p_assay.add_argument("--output", required=True, help="Output JSON file path")
# Range
p_range = subparsers.add_parser("range", help="Search by property range")
p_range.add_argument(
"--feature", required=True, help="Property name (e.g. molecular_weight)"
)
p_range.add_argument("--min", required=True, help="Minimum value")
p_range.add_argument("--max", required=True, help="Maximum value")
p_range.add_argument("--output", required=True, help="Output JSON file path")
args = parser.parse_args()
if args.command == "resolve":
data = resolve(name=args.name, inchi=args.inchi)
elif args.command == "properties":
data = properties(args.cid)
elif args.command == "synonyms":
data = synonyms(args.cid)
elif args.command == "safety":
data = safety(args.cid)
elif args.command == "pharmacology":
data = pharmacology(args.cid)
elif args.command == "view":
data = view(args.cid, args.heading)
elif args.command == "xrefs":
data = xrefs(args.cid, args.type)
elif args.command == "query":
data = query(args.path)
elif args.command == "image":
data = image(args.cid)
elif args.command == "similarity":
data = similarity(args.smiles)
elif args.command == "substructure":
data = substructure(args.smiles)
elif args.command == "assays":
data = assays(args.cid, active_only=args.active_only)
elif args.command == "range":
data = range_search(args.feature, args.min, args.max)
else:
print("Unknown command")
sys.exit(1)
write_output(data, args.output)
if __name__ == "__main__":
main()
Related skills
How it compares
Use pubchem-database for authoritative NCBI chemical records; use general HTTP skills only for non-chemistry public APIs.
FAQ
What PubChem API does pubchem-database use?
pubchem-database documents PUG-REST for computed properties and search plus PUG-View for detailed record views. Base REST paths follow /domain/namespace/identifiers/operation/output structure against pubchem.ncbi.nlm.nih.gov.
Which identifiers can pubchem-database search by?
pubchem-database supports PubChem namespaces including cid, exact chemical name, SMILES, and InChI keys. Paths target domains such as compound, substance, assay, gene, protein, pathway, taxonomy, and cell.
Is Pubchem Database safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.