# ChEMBL Bioactivity Normalizer & QC (`flintglade/chembl-bioactivity-normalizer-qc`) Actor

Normalize public ChEMBL bioactivity records into deterministic, analysis-ready rows with units, pChEMBL values, provenance, and explicit QC flags. Submit activity IDs or a bounded query; malformed and ambiguous records are uncharged.

- **URL**: https://apify.com/flintglade/chembl-bioactivity-normalizer-qc.md
- **Developed by:** [Flintglade](https://apify.com/flintglade) (community)
- **Categories:** Developer tools, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 normalized activities

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## ChEMBL Bioactivity Normalizer & QC

Turn official ChEMBL activity records into source-faithful, analysis-ready measurement rows with conservative molar normalization, explicit relation semantics, QC flags, provenance, and stable SHA-256 record hashes.

This Actor is for medicinal-chemistry, cheminformatics, structural-biology, and data-curation workflows that need to know what a measurement actually says before comparing it. It does **not** rank compounds, infer potency, or turn censored bounds into exact values.

### What you receive

Every admitted dataset row includes:

- original and standardized type, relation, value, units, and text value exactly as supplied by ChEMBL;
- activity, assay, molecule, target, and document identifiers;
- a molar value only when the standard numeric value, unit, and relation can be interpreted safely;
- an explicit relation class (`exact`, `upper_bound`, `lower_bound`, `approximate`, or `unknown_relation`);
- a conservative comparability class and human-review grouping key;
- sorted QC flags and exclusion reasons, including ChEMBL validity comments without suppression;
- a deterministic record hash that ignores only retrieval/run metadata;
- record-level ChEMBL source, retrieval, attribution, license, and ShareAlike fields.

Unsupported measurements are still useful QC outcomes. For example, a percent-inhibition record is returned as `not_molar_comparable` with an `unsupported_unit` flag; it is never silently converted or discarded.

### Input

Supply activity IDs, one constrained query, or both. The Actor accepts no arbitrary URL, header, cookie, credential, webhook, file, or executable input.

Direct records:

```json
{
  "activityIds": [31863],
  "maxConcurrency": 2,
  "requestTimeoutSeconds": 20,
  "maxRetries": 3
}
````

Bounded query:

```json
{
  "query": {
    "targetChemblId": "CHEMBL204",
    "standardType": "IC50",
    "maxRecords": 100
  }
}
```

Query filters are exact ChEMBL IDs for a molecule, target, assay, or document, plus an optional standard type. `maxRecords` is required and capped at 5,000. Concurrency is capped at 3 and all requests go only to the official HTTPS ChEMBL API.

### Output example

```json
{
  "schemaVersion": "chembl-normalized-activity/v1",
  "activityId": 31863,
  "canonicalMolarValue": 0.0001,
  "relationClass": "lower_bound",
  "comparabilityClass": "normalized_censored",
  "qcFlags": ["censored_relation"],
  "exclusionReasons": [],
  "sourceName": "ChEMBL",
  "sourceLicense": "CC BY-SA 3.0",
  "recordHash": "64-lowercase-hex-characters",
  "retrievedAt": "UTC RFC 3339 timestamp",
  "runId": "non-secret run identifier"
}
```

The actual row also contains the complete documented identifier, measurement, context, validity, attribution, source URL, and ShareAlike fields. A final aggregate summary is written uncharged to the `RUN_SUMMARY` key-value record rather than the paid dataset. It reports rows written and events charged separately, so local non-PPE testing remains truthful.

### Normalization rules

Only exact `M`, `mM`, `uM`, `µM`, `μM`, `nM`, and `pM` tokens are recognized as molar concentration units. The original unit text is always retained. A canonical molar value is emitted only when the standard value is finite and strictly positive and its relation is one of `=`, `<`, `<=`, `>`, `>=`, or `~`.

| Source relation | Meaning preserved | Comparability class when molar |
| --------------- | ----------------- | ------------------------------ |
| `=`             | exact             | `normalized_exact`             |
| `<`, `<=`       | upper bound       | `normalized_censored`          |
| `>`, `>=`       | lower bound       | `normalized_censored`          |
| `~`             | approximate       | `normalized_approximate`       |
| missing/other   | unknown           | `not_molar_comparable`         |

The grouping key means only “eligible for human review together.” Assays can differ for many scientifically important reasons. This Actor never aggregates, averages, imputes, ranks, or claims interchangeability.

### Pay per event

- `normalized-activity`: **$0.006 per successfully written result row**.
- Apify supplies the separate synthetic Actor-start event.
- Source failures, invalid inputs, malformed/unidentifiable source records, and work stopped before output are not charged a row event.
- A valid but unsupported measurement is a paid QC transformation because it preserves the source record and explains why it should not be treated as molar-comparable.
- The Actor checks the run’s charge limit before starting or admitting more work and stops with a bounded summary when the limit is reached.
- Platform usage is included in the pay-per-event price.

### Source, license, and attribution

Data is retrieved only from the official ChEMBL activity API. Every output row attributes **ChEMBL**, links the source record, records retrieval time, identifies **CC BY-SA 3.0**, links the license, and states that derived output remains subject to attribution and ShareAlike. The Actor does not fetch or republish commercially calculated molecule-property fields or third-party structures.

Unofficial transformation tool; not affiliated with or endorsed by ChEMBL or EMBL-EBI.

ChEMBL-derived output remains subject to [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/). Review ChEMBL’s current terms and attribution guidance for your downstream use.

### Privacy and security

The Actor has Limited permissions, no Standby server, no arbitrary network destinations, and no credential-bearing input. It does not put raw HTTP bodies, response headers, environment values, machine/user names, local paths, tokens, or cookies in results. Inputs, normalized rows, and the run summary use Apify storage according to the retention and access settings of your Apify account.

### Limits

- This is deterministic transformation and QC, not medicinal, clinical, safety, efficacy, or treatment advice.
- A normalized value does not prove that two assays are scientifically interchangeable.
- Source outages can yield a truthful partial run. The summary reports source failures and partial coverage.
- Upstream ChEMBL corrections can change deterministic fields and therefore the record hash in a later run.
- v0.1 does not fetch structures, calculated molecular properties, abstracts, or third-party enrichment.

### Support

Flintglade · `support@flintglade.com`

# Actor input Schema

## `activityIds` (type: `array`):

Positive numeric ChEMBL activity IDs. Duplicates are removed and reported.

## `query` (type: `object`):

Optional exact ChEMBL identifier filters and a required result cap.

## `maxConcurrency` (type: `integer`):

Maximum simultaneous official ChEMBL requests; never above 3.

## `requestTimeoutSeconds` (type: `integer`):

Per-request timeout from 5 to 30 seconds.

## `maxRetries` (type: `integer`):

Retries for bounded network errors, HTTP 408, 429, and 5xx only.

## Actor input object example

```json
{
  "activityIds": [
    31863
  ],
  "maxConcurrency": 2,
  "requestTimeoutSeconds": 20,
  "maxRetries": 3
}
```

# Actor output Schema

## `results` (type: `string`):

Source-faithful ChEMBL measurement, QC, provenance, and stable hash rows.

## `runSummary` (type: `string`):

Uncharged aggregate counts and partial-run diagnostics.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("flintglade/chembl-bioactivity-normalizer-qc").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("flintglade/chembl-bioactivity-normalizer-qc").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call flintglade/chembl-bioactivity-normalizer-qc --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=flintglade/chembl-bioactivity-normalizer-qc",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "ChEMBL Bioactivity Normalizer & QC",
        "description": "Normalize public ChEMBL bioactivity records into deterministic, analysis-ready rows with units, pChEMBL values, provenance, and explicit QC flags. Submit activity IDs or a bounded query; malformed and ambiguous records are uncharged.",
        "version": "0.1",
        "x-build-id": "WV6uvxZtoL2ju4CrN"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/flintglade~chembl-bioactivity-normalizer-qc/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-flintglade-chembl-bioactivity-normalizer-qc",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/flintglade~chembl-bioactivity-normalizer-qc/runs": {
            "post": {
                "operationId": "runs-sync-flintglade-chembl-bioactivity-normalizer-qc",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/flintglade~chembl-bioactivity-normalizer-qc/run-sync": {
            "post": {
                "operationId": "run-sync-flintglade-chembl-bioactivity-normalizer-qc",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "activityIds": {
                        "title": "ChEMBL activity IDs",
                        "maxItems": 10000,
                        "type": "array",
                        "description": "Positive numeric ChEMBL activity IDs. Duplicates are removed and reported.",
                        "items": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "default": [
                            31863
                        ]
                    },
                    "query": {
                        "title": "Constrained official-API query",
                        "required": [
                            "maxRecords"
                        ],
                        "type": "object",
                        "description": "Optional exact ChEMBL identifier filters and a required result cap.",
                        "properties": {
                            "moleculeChemblId": {
                                "title": "Molecule ChEMBL ID",
                                "description": "Exact uppercase molecule ChEMBL identifier.",
                                "type": "string",
                                "pattern": "^CHEMBL[1-9][0-9]{0,19}$"
                            },
                            "targetChemblId": {
                                "title": "Target ChEMBL ID",
                                "description": "Exact uppercase target ChEMBL identifier.",
                                "type": "string",
                                "pattern": "^CHEMBL[1-9][0-9]{0,19}$"
                            },
                            "assayChemblId": {
                                "title": "Assay ChEMBL ID",
                                "description": "Exact uppercase assay ChEMBL identifier.",
                                "type": "string",
                                "pattern": "^CHEMBL[1-9][0-9]{0,19}$"
                            },
                            "documentChemblId": {
                                "title": "Document ChEMBL ID",
                                "description": "Exact uppercase document ChEMBL identifier.",
                                "type": "string",
                                "pattern": "^CHEMBL[1-9][0-9]{0,19}$"
                            },
                            "standardType": {
                                "title": "Standard measurement type",
                                "description": "Optional exact standard type such as IC50 or Ki.",
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 100
                            },
                            "maxRecords": {
                                "title": "Maximum query records",
                                "description": "Hard upper bound on records requested by this query.",
                                "type": "integer",
                                "minimum": 1,
                                "maximum": 5000
                            }
                        },
                        "additionalProperties": false
                    },
                    "maxConcurrency": {
                        "title": "Maximum request concurrency",
                        "minimum": 1,
                        "maximum": 3,
                        "type": "integer",
                        "description": "Maximum simultaneous official ChEMBL requests; never above 3.",
                        "default": 2
                    },
                    "requestTimeoutSeconds": {
                        "title": "Request timeout (seconds)",
                        "minimum": 5,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Per-request timeout from 5 to 30 seconds.",
                        "default": 20
                    },
                    "maxRetries": {
                        "title": "Maximum retries",
                        "minimum": 0,
                        "maximum": 4,
                        "type": "integer",
                        "description": "Retries for bounded network errors, HTTP 408, 429, and 5xx only.",
                        "default": 3
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
