ChemistryAPI Guides

How to Run ADMET Screening on 1000 Molecules via API

Screen thousands of molecules for ADMET properties using the SciRouter API. Filter drug-like candidates by absorption, distribution, metabolism, excretion, and toxicity predictions.

Ryan Bethencourt
March 20, 2026
11 min read

Why ADMET Screening Matters

A molecule that binds perfectly to its target protein is worthless as a drug if the body cannot absorb it, if it is metabolized too quickly, if it accumulates in the wrong tissues, or if it is toxic. Roughly 90 percent of drug candidates fail in clinical trials, and poor pharmacokinetic (ADMET) properties are one of the top reasons.

Early ADMET screening catches these problems before you spend months and millions on synthesis and animal studies. By predicting absorption, distribution, metabolism, excretion, and toxicity computationally, you can filter out problematic compounds at the design stage and focus your experimental budget on the candidates most likely to succeed.

The Five ADMET Properties Explained

Absorption

Can the drug get into the bloodstream? Key properties include Caco-2 cell permeability (a proxy for intestinal absorption), human intestinal absorption (HIA), aqueous solubility, and P-glycoprotein substrate status (which affects efflux from cells).

Distribution

Where does the drug go once absorbed? Important properties include plasma protein binding (how much drug is bound to albumin vs. free), volume of distribution (Vd), and blood-brain barrier penetration (relevant for CNS drugs, and a red flag for non-CNS drugs).

Metabolism

How is the drug broken down? The main concern is cytochrome P450 (CYP) enzyme interactions. CYP inhibition can cause dangerous drug-drug interactions. CYP substrate status predicts which enzymes metabolize the compound and how quickly it is cleared.

Excretion

How fast is the drug eliminated? Half-life and clearance rate determine dosing frequency. Drugs cleared too quickly require frequent dosing; drugs cleared too slowly risk accumulation and toxicity.

Toxicity

Is the drug safe? Predictions include hERG channel inhibition (cardiac toxicity risk), AMES mutagenicity (cancer risk), hepatotoxicity (liver damage), and skin sensitization. A single positive toxicity flag can kill a drug candidate.

Prerequisites

You need Python 3.7+ and a SciRouter API key. Sign up at scirouter.ai/register for 500 free credits.

Install dependencies
pip install scirouter pandas
Set your API key
export SCIROUTER_API_KEY="sk-sci-your-api-key-here"

Step 1: Screen a Single Molecule

Start by screening one molecule to understand the API response format. Here we screen aspirin:

Screen a single molecule for ADMET
from scirouter import SciRouter

client = SciRouter()

# Screen aspirin
result = client.pharma.adme(smiles="CC(=O)Oc1ccccc1C(=O)O")

print("=== ADMET Profile for Aspirin ===")
print(f"Caco-2 permeability: {result.caco2_permeability:.2f} (log cm/s)")
print(f"Human intestinal absorption: {result.hia:.1f}%")
print(f"Plasma protein binding: {result.ppb:.1f}%")
print(f"BBB penetration: {'Yes' if result.bbb_penetrant else 'No'}")
print(f"CYP2D6 inhibitor: {'Yes' if result.cyp2d6_inhibitor else 'No'}")
print(f"CYP3A4 inhibitor: {'Yes' if result.cyp3a4_inhibitor else 'No'}")
print(f"Half-life: {result.half_life:.1f} hours")
print(f"hERG inhibitor: {'Yes' if result.herg_inhibitor else 'No'}")
print(f"AMES mutagenicity: {'Positive' if result.ames_positive else 'Negative'}")
print(f"Hepatotoxicity: {'Yes' if result.hepatotoxic else 'No'}")
print(f"Drug-likeness (QED): {result.qed:.2f}")
Note
QED (Quantitative Estimate of Drug-likeness) ranges from 0 to 1. Scores above 0.5 indicate reasonable drug-likeness. Most approved oral drugs score between 0.3 and 0.9.

Step 2: Screen a Batch of 1000 Molecules

For high-throughput screening, loop through a list of SMILES strings and collect results into a pandas DataFrame. Using concurrent requests keeps the total run time manageable:

Batch ADMET screening with concurrent requests
import pandas as pd
from concurrent.futures import ThreadPoolExecutor, as_completed
from scirouter import SciRouter
from scirouter.exceptions import SciRouterError

client = SciRouter()

# Load molecules from a CSV file (one SMILES per row)
# For this example, we define a small set inline
molecules = pd.read_csv("candidates.csv")  # columns: name, smiles
# Or define inline:
# molecules = pd.DataFrame({
#     "name": ["aspirin", "ibuprofen", "caffeine"],
#     "smiles": ["CC(=O)Oc1ccccc1C(=O)O", "CC(C)Cc1ccc(cc1)C(C)C(=O)O", "Cn1c(=O)c2c(ncn2C)n(C)c1=O"],
# })

def screen_one(name, smiles):
    """Screen a single molecule and return results as a dict."""
    try:
        r = client.pharma.adme(smiles=smiles)
        return {
            "name": name,
            "smiles": smiles,
            "caco2": r.caco2_permeability,
            "hia": r.hia,
            "ppb": r.ppb,
            "bbb": r.bbb_penetrant,
            "cyp2d6_inhibitor": r.cyp2d6_inhibitor,
            "cyp3a4_inhibitor": r.cyp3a4_inhibitor,
            "half_life": r.half_life,
            "herg": r.herg_inhibitor,
            "ames": r.ames_positive,
            "hepatotoxic": r.hepatotoxic,
            "qed": r.qed,
            "error": None,
        }
    except SciRouterError as e:
        return {"name": name, "smiles": smiles, "error": str(e)}

# Screen all molecules with 10 parallel workers
results = []
with ThreadPoolExecutor(max_workers=10) as pool:
    futures = {
        pool.submit(screen_one, row["name"], row["smiles"]): row["name"]
        for _, row in molecules.iterrows()
    }
    for i, future in enumerate(as_completed(futures)):
        result = future.result()
        results.append(result)
        if (i + 1) % 100 == 0:
            print(f"Screened {i + 1}/{len(molecules)} molecules...")

df = pd.DataFrame(results)
print(f"\nScreened {len(df)} molecules. Errors: {df['error'].notna().sum()}")
df.to_csv("admet_results.csv", index=False)

Step 3: Filter for Drug-Like Candidates

With ADMET predictions in hand, apply filters to identify the most promising compounds. A typical filter cascade removes molecules with toxicity flags, poor absorption, or unfavorable metabolism:

Filter drug-like candidates
import pandas as pd

df = pd.read_csv("admet_results.csv")
print(f"Starting compounds: {len(df)}")

# Remove molecules with errors
df = df[df["error"].isna()]
print(f"After removing errors: {len(df)}")

# Filter 1: No toxicity flags
df_safe = df[
    (df["herg"] == False) &           # no cardiac toxicity risk
    (df["ames"] == False) &           # no mutagenicity
    (df["hepatotoxic"] == False)      # no liver toxicity
]
print(f"After toxicity filter: {len(df_safe)}")

# Filter 2: Good absorption
df_absorb = df_safe[
    (df_safe["hia"] > 70) &           # >70% intestinal absorption
    (df_safe["caco2"] > -5.5)         # reasonable Caco-2 permeability
]
print(f"After absorption filter: {len(df_absorb)}")

# Filter 3: Acceptable metabolism (not CYP inhibitor)
df_metab = df_absorb[
    (df_absorb["cyp2d6_inhibitor"] == False) &
    (df_absorb["cyp3a4_inhibitor"] == False)
]
print(f"After metabolism filter: {len(df_metab)}")

# Filter 4: Drug-likeness
df_final = df_metab[df_metab["qed"] > 0.4]
print(f"After drug-likeness filter: {len(df_final)}")

# Rank by QED score
df_final = df_final.sort_values("qed", ascending=False)
print(f"\nTop 10 candidates:")
print(df_final[["name", "smiles", "qed", "hia", "half_life"]].head(10).to_string())

df_final.to_csv("drug_candidates.csv", index=False)
print(f"\nSaved {len(df_final)} candidates to drug_candidates.csv")
Tip
Adjust filter thresholds based on your therapeutic area. CNS drugs need BBB penetration. Oncology drugs may tolerate higher toxicity. Oral drugs need high HIA. Customize the cascade to match your project requirements.

Understanding the Results: A Practical Guide

Here is how to interpret key ADMET values in practice:

  • Caco-2 permeability above -5.15 log cm/s: Good intestinal permeability. Below -6.0 is poor.
  • HIA above 80%: Well absorbed orally. Below 30% suggests the molecule may need alternative delivery (injection, inhaled).
  • Plasma protein binding above 95%: Highly bound, less free drug available. May need higher doses.
  • hERG positive: Potential cardiac toxicity. This is a hard red flag — most programs will drop these compounds.
  • AMES positive: Mutagenic potential. Another hard red flag for most therapeutic areas.
  • Half-life 4 to 12 hours: Ideal range for once or twice daily dosing. Below 2 hours is challenging.
  • QED above 0.5: Reasonable drug-likeness. The average approved drug scores around 0.6.

Combining ADMET with Other Screens

ADMET screening is most powerful when combined with other computational filters. Here is a typical multi-stage screening funnel:

Multi-stage screening pipeline
from scirouter import SciRouter

client = SciRouter()

# Stage 1: Check drug-likeness with molecular properties
props = client.chemistry.properties(smiles="CC(=O)Oc1ccccc1C(=O)O")
if props.molecular_weight > 500 or props.logp > 5:
    print("FAIL: Violates Lipinski rules")

# Stage 2: ADMET screening
admet = client.pharma.adme(smiles="CC(=O)Oc1ccccc1C(=O)O")
if admet.herg_inhibitor or admet.ames_positive:
    print("FAIL: Toxicity flag")

# Stage 3: Dock against target (if ADMET passes)
# dock = client.docking.diffdock(protein_pdb=pdb, ligand_smiles=smiles)
# if dock.poses[0].confidence < 0.5:
#     print("FAIL: Poor binding prediction")

print("PASS: Candidate for experimental validation")

Performance and Throughput

Here is what to expect for batch screening at different scales:

  • 100 molecules: About 1 minute with 10 parallel workers
  • 1,000 molecules: About 5 to 10 minutes with 10 parallel workers
  • 10,000 molecules: About 50 to 100 minutes with 10 parallel workers (Pro tier recommended)
  • 100,000+ molecules: Contact SciRouter for enterprise batch processing

Each ADMET prediction costs 1 credit. Free tier accounts receive 500 credits per month. For large screening campaigns, the Pro tier provides higher rate limits and bulk pricing.

Exporting Results for Downstream Analysis

The CSV output from the screening pipeline integrates with standard cheminformatics workflows. Load it into DataWarrior for SAR analysis, feed it into Spotfire for visualization, or use it in a Jupyter notebook with RDKit for further filtering:

Visualize ADMET results
import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv("admet_results.csv")

fig, axes = plt.subplots(1, 3, figsize=(15, 5))

# Distribution of drug-likeness scores
axes[0].hist(df["qed"].dropna(), bins=30, color="#2563eb", edgecolor="white")
axes[0].set_xlabel("QED Score")
axes[0].set_ylabel("Count")
axes[0].set_title("Drug-Likeness Distribution")
axes[0].axvline(x=0.4, color="red", linestyle="--", label="Cutoff")
axes[0].legend()

# HIA vs Caco-2
axes[1].scatter(df["caco2"], df["hia"], alpha=0.3, s=10, color="#2563eb")
axes[1].set_xlabel("Caco-2 Permeability (log cm/s)")
axes[1].set_ylabel("Human Intestinal Absorption (%)")
axes[1].set_title("Absorption Properties")

# Toxicity flag distribution
tox_counts = pd.DataFrame({
    "Flag": ["hERG", "AMES", "Hepatotoxic"],
    "Count": [df["herg"].sum(), df["ames"].sum(), df["hepatotoxic"].sum()],
})
axes[2].bar(tox_counts["Flag"], tox_counts["Count"], color=["#ef4444", "#f59e0b", "#8b5cf6"])
axes[2].set_ylabel("Flagged Molecules")
axes[2].set_title("Toxicity Flags")

plt.tight_layout()
plt.savefig("admet_overview.png", dpi=150)
print("Saved admet_overview.png")

Next Steps

Now that you can screen molecules for ADMET properties at scale, integrate it into a complete drug discovery workflow. Use ADMET Prediction for pharmacokinetic screening, combine with DiffDock molecular docking to evaluate binding, and check Lipinski drug-likeness rules for basic property filtering.

For an automated pipeline that chains target prediction, molecular generation, docking, and ADMET screening into a single workflow, explore SciRouter Labs — our end-to-end drug discovery platform.

Sign up at scirouter.ai/register for 500 free credits and start screening molecules today.

Frequently Asked Questions

What does ADMET stand for?

ADMET stands for Absorption, Distribution, Metabolism, Excretion, and Toxicity. These are the five categories of pharmacokinetic and safety properties that determine whether a molecule can become a viable drug. Poor ADMET properties are the leading cause of drug candidate failure in clinical trials.

How accurate are AI ADMET predictions?

Modern AI ADMET models achieve 75 to 90 percent accuracy on standard benchmarks like TDC (Therapeutics Data Commons), depending on the specific property. Predictions are most reliable for well-studied properties like lipophilicity and Caco-2 permeability, and less reliable for complex endpoints like idiosyncratic toxicity.

How many molecules can I screen at once?

The API processes one molecule per request, but you can send requests concurrently. With 10 parallel workers, you can screen approximately 1000 molecules in 5 to 10 minutes. Free tier accounts are rate-limited to 60 requests per minute. Pro tier accounts support higher throughput.

What input format does the ADMET API accept?

The API accepts molecules as SMILES strings. SMILES is a text-based format for representing molecular structures. You can find SMILES for known compounds on PubChem or ChEMBL, or generate them from structure editors like the JSME editor.

Can I use this for regulatory submissions?

AI ADMET predictions are useful for prioritizing compounds in early discovery but are not a substitute for experimental ADMET studies required by regulatory agencies. FDA and EMA require in vitro and in vivo ADMET data for IND applications. Use these predictions to reduce the number of compounds you need to test experimentally.

Try this yourself

500 free credits. No credit card required.