← Back to blog

Bayesian prior elicitation for clinical trials: a practical guide with bayprior

Bayesian bayprior FDA 2026 Clinical trials

The FDA's 2026 draft guidance on Bayesian statistical methods for drug and biological products raises the bar for how sponsors justify and document their prior distributions. For teams using R, the bayprior package provides a structured workflow that takes you from expert elicitation through prior-data conflict diagnostics to a submission-ready justification report.

This guide walks through the core workflow with practical R code. All function signatures have been verified against the package documentation. We assume basic familiarity with Bayesian methods and a regulated environment where documentation matters.

Why prior justification is now a regulatory concern

The FDA's 2026 guidance makes explicit what was previously implicit: the prior distribution is not just a statistical choice — it is a regulatory claim that requires documented justification, sensitivity analysis, and evidence that the prior does not unduly influence the posterior in ways that conflict with the trial data.

Specifically, the guidance asks sponsors to:

bayprior is built to address each of these requirements in a single, integrated workflow.

Installation

install.packages("bayprior") # v0.2.12
library(bayprior)

An interactive Shiny application is also available for teams who prefer a point-and-click interface:

run_app()

Step 1: Eliciting the prior

bayprior supports three elicitation methods — moment matching, quantile matching, and the SHELF roulette method — across six distribution families: Beta, Normal, Gamma, Log-Normal, Exponential, and Weibull.

The most common scenario for a binary endpoint (e.g. response rate) is moment matching from a clinical expert's central estimate and uncertainty:

# Elicit a Beta prior on a response rate
# Expert believes: mean ~35%, SD ~10%
prior <- elicit_beta(
  mean      = 0.35,
  sd        = 0.10,
  method    = "moments",
  label     = "Response rate",
  expert_id = "Expert_1"
)

plot(prior)

For multi-expert elicitation, bayprior supports linear and logarithmic opinion pooling with pairwise Bhattacharyya agreement diagnostics:

e1  <- elicit_beta(mean = 0.30, sd = 0.10, method = "moments", expert_id = "E1")
e2  <- elicit_beta(mean = 0.42, sd = 0.12, method = "moments", expert_id = "E2")

agg <- aggregate_experts(list(E1 = e1, E2 = e2), weights = c(0.6, 0.4))

Step 2: Prior-data conflict diagnostics

Once trial data are available, prior_conflict() computes four complementary diagnostics: Box's prior predictive p-value, surprise index, Bhattacharyya overlap, and KL divergence. Binary, continuous, Poisson/count, and survival data types are all supported.

# Observed data: 18 responders out of 40 patients
cd <- prior_conflict(
  prior,
  list(type = "binary", x = 18, n = 40)
)

print(cd)

Box's p-value close to 0 or 1 indicates the observed data are surprising under the prior predictive distribution — a signal of potential conflict between the prior and the trial data.

Step 3: Sensitivity analysis

sensitivity_grid() evaluates posterior conclusions across a hyperparameter grid. The plot_tornado() function visualises the results:

sa <- sensitivity_grid(
  prior,
  data_summary = list(type = "binary", x = 18, n = 40),
  param_grid   = list(alpha = seq(1, 8, 0.5), beta = seq(2, 20, 1)),
  target       = c("posterior_mean", "prob_efficacy"),
  threshold    = 0.30
)

plot_tornado(sa)

This demonstrates to reviewers that conclusions are not uniquely dependent on a specific prior specification.

Step 4: Robust and sceptical priors

For regulatory sensitivity analyses, bayprior implements the robust mixture prior (Schmidli et al., 2014) and the sceptical prior (Spiegelhalter & Freedman, 1994):

rob  <- robust_prior(prior, vague_weight = 0.20)
scep <- sceptical_prior(null_value = 0.20, family = "beta", strength = "moderate")

Step 5: Generating the regulatory report

prior_report() generates a self-contained prior justification document in HTML, PDF, or Word format, designed for inclusion in a regulatory submission package:

prior_report(
  prior           = prior,
  conflict        = cd,
  sensitivity     = sa,
  robust_prior    = rob,
  sceptical_prior = scep,
  output_format   = "html",
  trial_name      = "TRIAL-001",
  sponsor         = "Example Pharma Ltd",
  author          = "N.P., Biostatistician"
)
PDF output requires Quarto CLI and a LaTeX installation. Run tinytex::install_tinytex() if needed.

References


Questions or corrections — hello@reprostats.org.