CDISC Controlled Terminology for RWE Submissions
CDISC Controlled Terminology (CT) is the versioned codelist package — published quarterly by CDISC in partnership with NCI-EVS — that supplies every coded value used in an SDTM or ADaM submission (route, location, frequency, severity, unit-of-measure mappings to UCUM, PARAMCDs, and so on); for RWE it also pins the version of MedDRA, WHODrug, and LOINC used to translate raw claims/EHR/registry codes into the submission vocabulary, with every version lock recorded in define.xml and the ADRG.
On this page
CDISC Controlled Terminology is the official values list that every coded field in an FDA submission must use. SDTM and ADaM define the structure of a variable; CT defines what the value has to be — every route, every unit, every severity grade comes from a CDISC-published list or from a partner vocabulary like MedDRA, WHODrug, LOINC, or UCUM. For real-world data the version pin is the audit signal that the translation from raw claims or EHR codes was performed against a fixed, named vocabulary release, not re-coded mid-study.
CDISC Controlled Terminology (CT)
is the set of machine-readable codelists CDISC publishes alongside SDTM and ADaM: for every SDTM variable flagged "(CT)" in the IG, permissible values are drawn from a published codelist (e.g., RACE, SEX, UNIT, ROUTE of administration, DOSAGE FORM, frequency, disposition reason). CT is versioned quarterly; the FDA Data Standards Catalog names which CT version applies to submissions received in a given window. Alongside CDISC CT, submission packages rely on partner terminologies: MedDRA for adverse events and medical history, WHODrug for medications, LOINC for laboratory tests, UCUM for units — each with its own version governance.
Why it matters for RWE
Real-world data arrives coded in source vocabularies — ICD-10-CM diagnosis codes, NDC drug codes, CPT/HCPCS procedures, SNOMED CT in EHRs, local lab panels. None of these are submission terminologies. Mapping RWD into SDTM/ADaM therefore always involves a two-stage vocabulary pipeline: source code → intermediate standard (often already done by the data vendor) → submission terminology (MedDRA PT, WHODrug B3 format, CDISC CT submission values). Each arrow is a lossy, versioned transformation that a regulatory reviewer may want to inspect, so the pipeline must be recorded — in SUPPQUAL variables preserving the source value, and in define.xml algorithms documenting the translation.
Operational mapping decisions in RWD
- Diagnoses → MedDRA: ICD-10-CM codes for incident events mapped to MedDRA preferred terms for AE/MH domains. Verbatim terms should preserve the source description; the MSSO browser's ICD-to-MedDRA mappings help, but ambiguous cases (an ICD code covering several PTs) require documented rules.
- Dispensings → WHODrug: NDC → generic ingredient/dosage form via a maintained cross-reference, then WHODrug B3 coding for CM/EX. NDCs are repackaged and reused — pin the NDC directory version and document it.
- Labs → LOINC + UCUM: EHR result strings and local codes mapped to LOINC; units harmonized to UCUM with conversion factors recorded.
- Submission-value enforcement: SDTM --DECOD/--TESTCD variables carry controlled submission values; free-text --TERM carries the source verbatim. Both are needed; collapsing them destroys traceability.
Version governance
- Lock versions at build time: MedDRA, WHODrug, LOINC, UCUM, and CDISC CT versions are stamped into define.xml and the ADRG. Re-coding after a MedDRA annual release is a documented version change, not a silent update.
- Extensible codelists: some codelists (e.g., certain --CAT values) permit sponsor extensions ("EXTENSIBLE"); extensions require justification and reviewer burden. Never invent values inside non-extensible codelists — the conformance validator rejects them.
- Cross-version consistency: multi-study RWE packages spanning years may carry different MedDRA versions per study; document per-dataset versions rather than force-unifying.
Pros, cons, and trade-offs
- vs free-text values: controlled terms let the Pinnacle 21 validator machine-check the whole package; free text is flexible but unverifiable at scale.
- vs sponsor-defined terms everywhere: standard terms travel without explanation; use extensible-codelist extensions only where no standard term exists.
- Trade-off: granularity vs coding effort — ICD-10-CM→MedDRA loses specificity; keep the source code in SUPPQUAL rather than inventing non-standard terms.
When NOT to use
Not as a substitute for source-vocabulary fidelity — preserve original ICD/NDC/local values in SUPPQUAL whenever the controlled term is coarser. And do not mix terminology versions mid-package; lock, document, finish.
Decision diagram
flowchart LR R[Raw RWD codes<br/>ICD-10-CM, NDC, LOINC, SNOMED] --> T[Translate to CDISC CT values<br/>using locked package versions] T --> CT[CDISC CT quarterly release] T --> MD[MedDRA preferred terms] T --> WD[WHODrug preferred names] T --> LC[LOINC codes] T --> UC[UCUM units] CT --> L[Lock versions in define.xml + ADRG] MD --> L WD --> L LC --> L UC --> L L --> V[Pinnacle 21 conformance<br/>against locked versions] V --> F[FDA submission<br/>package]
Worked example
Scenario
We need to lock the controlled terminology versions for an FDA submission built from a claims-derived SDTM. Three version pins must be recorded: the CDISC CT package version used to populate EXROUTE, AESEV, AGEU, PARAMCD and similar values; the MedDRA version used to translate ICD-10-CM diagnoses into MedDRA preferred terms for the AE and MH domains; and the WHODrug version used to translate NDC codes into preferred drug names for the EX and CM domains. All three go into define.xml codelist metadata and the ADRG narrative.
Dataset
Three terminology version locks for a claims-derived SDTM submission.
| vocabulary | package | version_locked | used_for | where_recorded |
|---|---|---|---|---|
| CDISC CT - 2024-09-26 quarterly release - 2024-09-26 - EXROUTE | AESEV | AGEU | PARAMCD | ... - define.xml codelist + ADRG |
| MedDRA - MSSO biannual release - MedDRA 27.1 (Sep 2024) - AE and MH coded values - define.xml + SDRG + ADRG | ||||
| WHODrug Global - UMC biannual release - C3 format | 2024-09 release - EXTRT and CMTRT for medications - define.xml + ADRG | |||
| UCUM - stable - current as of build - LBORRESU | VSORRESU | EXDOSU - define.xml variable metadata | ||
| ICD-10-CM (US) - annual release (CDC/NCHS) - FY2024 - AETERM / MHDECOD source vocabulary - define.xml algorithm + ADRG |
Steps
Result
All five vocabulary versions are pinned: CDISC CT 2024-09-26, MedDRA 27.1, WHODrug Global 2024-09 (C3), UCUM current, ICD-10-CM FY2024. The ADRG narrative records each lock; the define.xml codelist metadata carries the versions into the submission package; the Pinnacle 21 run validates against them. A reviewer can re-derive any coded value.
Trade-offs
Runnable example
Loads the CDISC CT package and materializes a version-lock metadata object that goes into define.xml and the ADRG.
import pandas as pd
import json, zipfile
# Lock the CT package version at SDTM build time.
CDISC_CT_VERSION = "2024-09-26" # CDISC CT quarterly release
MEDDRA_VERSION = "27.1" # MSSO biannual release
WHODRUG_VERSION = "2024-09" # UMC biannual release, C3 format
UCUM_VERSION = "current"
def load_cdisc_ct(ct_zip_path: str) -> dict:
# Returns a {codelist_name: [submission_values]} dict from the CDISC CT Excel/CSV inside the zip.
with zipfile.ZipFile(ct_zip_path) as zf:
# The CDISC CT package publishes a single spreadsheet; load it and index by codelist name.
ct_file = [n for n in zf.namelist() if n.endswith((".xlsx", ".csv"))][0]
df = pd.read_csv(zf.open(ct_file)) if ct_file.endswith(".csv") \
else pd.read_excel(zf.open(ct_file))
return {row["Codelist Name"]: row["CDISC Submission Value"]
for _, row in df.iterrows()}
def build_define_metadata() -> dict:
# Materialize the version-lock metadata that goes into define.xml + ADRG.
return {
"cdisc_ct": {"package": "CDISC CT", "version": CDISC_CT_VERSION},
"meddra": {"package": "MedDRA", "version": MEDDRA_VERSION},
"whodrug": {"package": "WHODrug", "version": WHODRUG_VERSION},
"ucum": {"package": "UCUM", "version": UCUM_VERSION},
}
R version using jsonlite; emits the version-lock metadata as JSON for the ADRG.
library(jsonlite)
CDISC_CT_VERSION <- "2024-09-26"
MEDDRA_VERSION <- "27.1"
WHODRUG_VERSION <- "2024-09"
UCUM_VERSION <- "current"
build_define_metadata <- function() {
list(
cdisc_ct = list(package = "CDISC CT", version = CDISC_CT_VERSION),
meddra = list(package = "MedDRA", version = MEDDRA_VERSION),
whodrug = list(package = "WHODrug", version = WHODRUG_VERSION),
ucum = list(package = "UCUM", version = UCUM_VERSION)
)
}
write_define_lock <- function(path) {
jsonlite::write_json(build_define_metadata(), path = path, pretty = TRUE, auto_unbox = TRUE)
}
SAS version using PROC EXPORT to materialize the version locks as CSV for the submission package.
/* Lock the CT package versions at SDTM build time. */
%let cdisc_ct_version = 2024-09-26;
%let meddra_version = 27.1;
%let whodrug_version = 2024-09;
%let ucum_version = current;
/* Write a small metadata file with the locked versions for define.xml + ADRG. */
data work.ct_locks;
length package $20 version $20;
package = "CDISC CT"; version = "&cdisc_ct_version"; output;
package = "MedDRA"; version = "&meddra_version"; output;
package = "WHODrug"; version = "&whodrug_version"; output;
package = "UCUM"; version = "&ucum_version"; output;
run;
proc export data=work.ct_locks
outfile="ct_version_locks.csv"
dbms=csv replace;
run;
Citations
- [1]CDISC. Controlled Terminology. CDISC standards.
- [2]U.S. Food and Drug Administration. Providing Regulatory Submissions in Electronic Format — Standardized Study Data. FDA Guidance for Industry.
- [3]MedDRA MSSO. MedDRA Support Documentation. Medical Dictionary for Regulatory Activities, Maintenance and Support Services Organization.