openFDA Pharmacovigilance Explorer

Real-time Signal Detection in Drug Safety

Manuel Maturano

2026-03-01

1. The Challenge in Pharmacovigilance

Post-marketing drug safety relies heavily on spontaneous reporting systems. However, extracting meaningful signals from massive databases like the FDA Adverse Event Reporting System (FAERS) can be technically challenging for health professionals.

The Solution: The openFDA Explorer is a Shiny web application designed to facilitate access to this data. It provides an intuitive interface to query the FDA API in real-time, allowing users to:

  • Analyze demographic profiles of hospitalized patients for specific drugs.
  • Identify culprit drugs for specific adverse reactions (syndromes).
  • Calculate Disproportionality measures on the fly.

2. Interactive Analysis Panels

The application is divided into two main analytical workflows:

Panel A: Drug-Centric Safety Users input a generic drug name (e.g., ROSIGLITAZONE) and apply seriousness filters. The app retrieves the latest reports, displaying the age/sex distribution of affected patients and the top 10 reported adverse reactions.

Panel B: Syndrome-Centric Signal Detection Users input a medical condition (e.g., HEPATIC FAILURE). The app identifies the top drugs associated with this condition and calculates the Reporting Odds Ratio (ROR) to flag potential safety signals.

3. Data Processing & Efficiency

The application queries the official openFDA API directly. No local databases are required, ensuring the data is always up-to-date.

To handle the complex JSON responses and perform fast data aggregations, the core engine relies on the data.table package. This ensures that even when making multiple API calls to build the 2x2 tables required for signal detection, the application remains responsive and efficient.

Progress indicators (shinyjs) keep the user informed during the API fetch cycles.

4. Under the Hood: The ROR Calculation

The core statistical engine calculates the Reporting Odds Ratio (ROR) with 95% Confidence Intervals. Here is a simplified demonstration of the underlying logic used in Panel B:

# Simulated 2x2 table data for Drug X and Syndrome Y

a <- 150 # Drug X + Syndrome Y 
b <- 5000 # Drug X + Other Syndromes 
c <- 800 # Other Drugs + Syndrome Y 
d <- 95000 # Other Drugs + Other Syndromes

# ROR Calculation

ror_val <- (a * d) / (b * c) 
se_ln <- sqrt(1/a + 1/b + 1/c + 1/d) 
ci_lower <- exp(log(ror_val) - 1.96 * se_ln)

cat(sprintf("ROR: %.2f (Lower 95%% CI: %.2f)", ror_val, ci_lower))
ROR: 3.56 (Lower 95% CI: 2.99)