- Family history of premature ASCVD: males <55 y; females <65 y.
- Primary hypercholesterolemia: LDL-C 160–189 mg/dL (4.1–4.8 mmol/L) or non-HDL-C 190–219 mg/dL (4.9–5.6 mmol/L).
- Chronic kidney disease: eGFR 15–59 mL/min/1.73 m² (± albuminuria), not on dialysis or post-transplant.
- Chronic inflammatory conditions: e.g., psoriasis, rheumatoid arthritis, SLE, HIV.
- Women’s risk: premature menopause (<40 y) or adverse pregnancy outcomes.
- Persistent hypertriglyceridemia: ≥175 mg/dL (non-fasting).
- Elevated biomarkers (if measured): hs-CRP ≥2.0 mg/L; Lp(a) ≥50 mg/dL (≥125 nmol/L); ApoB ≥130 mg/dL; ABI <0.9.
PREVENT™ Risk Calculator
- This is an unofficial implementation powered by the open-source {preventr} package (MIT license). It follows the AHA PREVENT™ equations and includes optional predictors UACR, HbA1c, and SDI.
- PREVENT™ is validated for adults 30–79 years without known CVD; outside this range the estimates may be unreliable.
- Units: Cholesterol inputs are taken in mg/dL (a toggle converts from mmol/L automatically). eGFR is in mL/min/1.73m². UACR in mg/g; HbA1c in percent.
- Trademark: PREVENT™ is a trademark of the American Heart Association.
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 780
# Minimal PREVENT™ calculator using R Shiny + Shinylive + preventr
# Packages are installed at runtime in the browser using webR.
# Install packages (first render will download ~ few MB)
webr::install(c("shiny", "preventr", "dplyr"))
library(shiny)
library(preventr)
library(dplyr)
ui <- fluidPage(
tags$head(tags$style(HTML('
.container-fluid { max-width: 1150px; }
.help-text { font-size: 0.9rem; color: #666; }
.alert { margin-top: 10px; }
.well { background: #EDA8A8; border-radius: 14px; border: 1px solid #EDA8A8; }
.form-control, .selectize-control, .irs { font-size: 0.95rem; }
.result-table table { width: 100%; border-collapse: collapse; }
.result-table th, .result-table td { padding: 10px 12px; border-bottom: 1px solid #EDA8A8; }
.result-table th { text-transform: uppercase; letter-spacing: .02em; font-size: .95rem; font-weight: 900; color: #000000; }
'))),
titlePanel("PREVENT™ Risk Calculator"),
fluidRow(
column(5,
div(class = "well",
tags$h4("Required inputs"),
sliderInput("age", "Age (years)", min = 18, max = 90, value = 50),
selectInput("sex", "Sex", choices = c("Female", "Male"), selected = "Female"),
numericInput("sbp", "Systolic BP (mmHg)", value = 120, min = 70, max = 250, step = 1),
checkboxInput("bp_tx", "On antihypertensive treatment", value = FALSE),
radioButtons("chol_unit", "Cholesterol units", c("mg/dL", "mmol/L"), inline = TRUE),
numericInput("tc", "Total Cholesterol", value = 200, min = 50, max = 500),
numericInput("hdl", "HDL Cholesterol", value = 50, min = 10, max = 150),
checkboxInput("statin", "On statin therapy", value = FALSE),
checkboxInput("diabetes", "Diabetes present", value = FALSE),
checkboxInput("smoking", "Current smoker", value = FALSE),
numericInput("egfr", "eGFR (mL/min/1.73m²)", value = 90, min = 5, max = 120),
numericInput("bmi", "BMI (kg/m²)", value = 25, min = 10, max = 60)
),
div(class = "well",
tags$h4("Model options"),
selectInput("model", "PREVENT model", choices = c(
"Base" = "base",
"+ UACR" = "acr",
"+ HbA1c" = "hba1c",
"+ SDI" = "sdi",
"Full (UACR + HbA1c + SDI)" = "full"), selected = "base"),
conditionalPanel(
condition = "input.model == 'acr' || input.model == 'full'",
numericInput("acr", "UACR (mg/g)", value = NA, min = 1, max = 2000)
),
conditionalPanel(
condition = "input.model == 'hba1c' || input.model == 'full'",
numericInput("hba1c", "Hemoglobin A1c (%)", value = NA, min = 3, max = 20)
),
conditionalPanel(
condition = "input.model == 'sdi' || input.model == 'full'",
sliderInput("sdi", "Social Deprivation Index (decile)", min = 1, max = 10, value = 5)
),
actionButton("calc", "Calculate risk", class = "btn btn-primary")
),
div(class = "help-text",
"Validated for ages 30–79 years without known CVD. Units: total/HDL cholesterol in ",
tags$code("mg/dL"), ", eGFR in mL/min/1.73m², UACR in mg/g, HbA1c in %."
)
),
column(7,
uiOutput("alerts"),
div(class = "result-table", tableOutput("results")),
br(),
div(class = "help-text",
tags$em("Outputs are separate models: total CVD, ASCVD, and heart failure are independent; sums can exceed total CVD."))
)
)
)
# ---- server ----
server <- function(input, output, session) {
# helper: convert mmol/L to mg/dL for chol values
to_mgdl <- function(x, unit) {
if (is.null(x) || is.na(x)) return(NA_real_)
if (identical(unit, "mmol/L")) x * 38.67 else x
}
derivation_warnings <- reactive({
msgs <- character()
if (input$age < 30 || input$age > 79) msgs <- c(msgs, "Age is outside the 30–79 y validation range.")
if (input$sbp < 90 || input$sbp > 200) msgs <- c(msgs, "SBP outside 90–200 mmHg derivation range.")
if (to_mgdl(input$tc, input$chol_unit) < 130 || to_mgdl(input$tc, input$chol_unit) > 320)
msgs <- c(msgs, "Total cholesterol outside 130–320 mg/dL derivation range.")
if (to_mgdl(input$hdl, input$chol_unit) < 20 || to_mgdl(input$hdl, input$chol_unit) > 100)
msgs <- c(msgs, "HDL-C outside 20–100 mg/dL derivation range.")
if (input$bmi < 18.5 || input$bmi > 40)
msgs <- c(msgs, "BMI outside 18.5–40 kg/m² derivation range.")
if (input$egfr < 15 || input$egfr > 120)
msgs <- c(msgs, "eGFR unusual; ensure units are mL/min/1.73m².")
msgs
})
output$alerts <- renderUI({
msgs <- derivation_warnings()
if (!length(msgs)) return(NULL)
div(class = "alert alert-warning", HTML(paste(msgs, collapse = "<br>")))
})
# Compute on click
current <- eventReactive(input$calc, {
list(
age = input$age,
sex = tolower(input$sex),
sbp = input$sbp,
bp_tx = isTRUE(input$bp_tx),
total_c = to_mgdl(input$tc, input$chol_unit),
hdl_c = to_mgdl(input$hdl, input$chol_unit),
statin = isTRUE(input$statin),
dm = isTRUE(input$diabetes),
smoking = isTRUE(input$smoking),
egfr = input$egfr,
bmi = input$bmi,
model = input$model,
uacr = if (!is.null(input$acr)) input$acr else NA_real_,
hba1c = if (!is.null(input$hba1c)) input$hba1c else NA_real_,
sdi = if (!is.null(input$sdi)) input$sdi else NA_real_
)
}, ignoreInit = TRUE)
# Main computation using preventr::estimate_risk()
est <- reactive({
req(current())
x <- current()
args <- list(
age = x$age,
sex = x$sex, # 'female' or 'male'
sbp = x$sbp,
bp_tx = x$bp_tx,
total_c = x$total_c,
hdl_c = x$hdl_c,
statin = x$statin,
dm = x$dm,
smoking = x$smoking,
egfr = x$egfr,
bmi = x$bmi,
model = x$model
)
if (x$model %in% c("acr", "full")) args$uacr <- x$uacr
if (x$model %in% c("hba1c", "full")) args$hba1c <- x$hba1c
if (x$model %in% c("sdi", "full")) args$sdi <- x$sdi
do.call(preventr::estimate_risk, args)
})
output$results <- renderTable({
res <- est()
r10 <- res$risk_est_10yr |> select(total_cvd, ascvd, heart_failure, chd, stroke)
r30 <- res$risk_est_30yr |> select(total_cvd, ascvd, heart_failure, chd, stroke)
fmt <- function(v) sprintf("%.1f%%", 100 * v)
data.frame(
Outcome = c("Total CVD", "ASCVD", "Heart Failure", "CHD", "Stroke"),
`10-year` = sapply(r10[1,], fmt),
`30-year` = sapply(r30[1,], fmt),
check.names = FALSE
)
}, striped = TRUE, bordered = FALSE, align = "lcc")
}
shinyApp(ui, server)
How to Use and Interpret PREVENT Equation Results
The PREVENT equations estimate absolute 10-year and 30-year risk for total CVD (PREVENT-CVD), ASCVD (PREVENT-ASCVD) and HF (PREVENT-HF).
Guideline-Based Use
The 2025 AHA/ACC High Blood Pressure Guideline recommends using the PREVENT-CVD outcome-specific equation to estimate 10-year risk of total CVD to inform management decisions for Stage 1 hypertension (systolic blood pressure 130–139 mm Hg or diastolic blood pressure 80–89 mm Hg) among adults without known CVD, diabetes, or chronic kidney disease.
Adults at increased CVD risk with the PREVENT-CVD equations — defined as a 10-year total CVD risk ≥7.5% — are recommended to initiate anti-hypertensive therapy for Stage 1 hypertension.
Cholesterol and Heart Failure Decisions
For management decisions about cholesterol and heart failure prevention therapies, the PREVENT-ASCVD and PREVENT-HF equations may help inform clinician–patient discussions.
Until updated guidance becomes available with specific risk thresholds: - Continue to use the Pooled Cohort Equations (PCEs) to guide statin initiation
- Follow current recommendations for HF prevention from the latest HF guideline
Limitations
Other co-existing conditions may lead to underestimation of an individual patient’s absolute CVD risk. These are described as Risk Enhancing Factors in the 2019 Primary Prevention Guidelines.