← Methods repository
concept

PICOTS Framework for RWE

A structured question-framing scaffold (Population, Intervention/exposure, Comparator, Outcome, Timing, Setting/study design) that forces every operational decision in a real-world evidence study to be pre-specified before any code list, eligibility rule, or estimand is fixed.

Framework_Standardpicotspicoresearch-questionprotocol-developmentfit-for-purposetarget-trialevidence-synthesisestimand
Methods reference only. Use primary source citations and local policy before applying this in a study protocol, regulatory submission, payer dossier, or clinical decision.

In plain language

PICOTS is a six-part checklist that forces a researcher to write down exactly who will be studied, what treatment will be compared against what, what counts as the outcome, how long patients will be followed, and which database will be used — before a single line of code is written. Think of it as filling out a very precise order form: if any box is left blank, the study cannot be built without guessing, and guessing introduces errors that are almost impossible to fix later. The six letters stand for Population, Intervention, Comparator, Outcome, Timing, and Setting.

PICOTS

extends the classic PICO scaffold of evidence-based medicine with two elements that the randomized-trial world can take for granted but that dominate the validity of a real-world evidence (RWE) study: Timing and Setting. In an RCT the protocol fixes who is randomized, when the clock starts, how long they are followed, and where the data come from. In a database study none of that is given — it must be reconstructed from claims or EHR records — so PICOTS is less a literature-search heuristic than the master specification from which the eligibility logic, time-zero rule, exposure/outcome algorithms, and the estimand are derived. Each letter is a contract: P (the cohort and its lookback/washout), I (the exposure strategy and how initiation is coded), C (the reference strategy — usually an active comparator), O (the endpoint and its validated algorithm), T (lookback, washout, induction/latency, grace, follow-up, censoring), and S (the data source(s), care system, geography, calendar window, and the analytic design that ties it together).

Core conceptual distinction

. PICOTS is a framing and specification layer, not an estimation method. Its job is to make the research question answerable and the protocol auditable before any model is fit; it does not, by itself, control confounding, handle time-varying treatment, or define a summary measure. The single most consequential distinction it enforces is that PICOTS is upstream of the estimand: P + I/C + O pin down three of the five estimand attributes (population, treatment, endpoint); T (timing) informs but does not by itself fix the remaining two — the population-level summary (ATE vs ATT) and the intercurrent-event strategy — which the estimand must still add. A vague PICOTS therefore guarantees a vague estimand. Equally, PICOTS is the layer where time-zero is defined — the most common source of avoidable bias in RWE — by forcing T and S to specify exactly when follow-up starts and what enrollment must be observed before it. A second distinction: PICOTS frames a question, whereas the target-trial framework operationalizes that question into a protocol; PICOTS feeds the target trial (eligibility = P + S + T_lookback; assignment = I + C; follow-up + outcome = T + O), it does not replace it.

Pros, cons, and trade-offs

— specific and comparative. - vs an unstructured "research question" paragraph: PICOTS forces each operational decision into the open, exposes the under-specified element (almost always T or S), and makes the protocol reviewable against FDA, ENCePP/EMA, and HTA expectations. Cost: a well-filled PICOTS table can give a false sense of completeness — it names the elements but does not test whether the comparator is clinically interchangeable or whether positivity holds. Prefer PICOTS as the entry point for any RWE protocol; it is nearly free and prevents post-hoc eligibility drift. - vs PICO (without T and S): plain PICO is adequate for an RCT systematic-review question where timing and setting are fixed by the trials being summarized. In RWE, dropping T re-admits immortal-time and induction/latency errors, and dropping S hides the data-source failure modes (MA-only person-time, EHR leakage) that decide whether the question is even answerable. Prefer PICOTS over PICO for any database study or target-trial emulation. - vs the target-trial / estimand framework: PICOTS is simpler, faster to communicate, and is the natural front end of both. It is, however, deliberately silent on intercurrent-event handling, the population-level summary (ATE vs ATT), and time-varying confounding — for those you must move down to the estimand and g-methods layers. Prefer PICOTS to scope and align stakeholders first, then refine into a target-trial protocol plus a written estimand. The two are complements, not substitutes.

When to use

. As the first artifact of essentially every RWE protocol, SAP, fit-for-purpose assessment, or evidence-synthesis question: comparative effectiveness/safety studies, target-trial emulations, single-arm-vs-external-control designs, HTA-facing comparative analyses, and multi-database/distributed studies that need one common question with locally adapted code lists. Present it as a table — its discipline is the single most effective guard against the "we'll figure out the population later" drift that produces post-hoc eligibility changes and irreproducible cohorts. Use it to negotiate scope with clinical and regulatory stakeholders before a line of extraction code is written.

When NOT to use — and when it is actively misleading or dangerous

. - As a substitute for an estimand or analysis plan. A complete PICOTS table that omits the intercurrent-event strategy (death, treatment switching, discontinuation) and the summary measure is not a finished design. Treating "we wrote a PICOTS table" as sufficient is how protocols reach analysis with an undefined estimand and an ITT-vs-per-protocol ambiguity discovered only at review. - When the C element is filled in mechanically. Naming a comparator does not make it valid. If the comparator treats a different indication, a different line of therapy, or systematically different patients, PICOTS will look complete while re-importing confounding by indication and channeling — the bias the design exists to remove. PICOTS does not check interchangeability; clinical review and baseline balance do. - When T is specified on paper but contradicted by the data's coverage. A 36-month follow-up window in S = commercial claims, where median continuous enrollment is ~2 years, is a specification that the data cannot honor; the gap silently becomes differential administrative censoring. A PICOTS that is internally tidy but incompatible with the chosen S is worse than none, because it confers false confidence. - For purely descriptive or hypothesis-generating exploration where forcing a single C and a fixed T would prematurely narrow an exploratory aim. Use a looser descriptive frame and reserve PICOTS for the confirmatory question that follows.

Data-source operational depth

. - Claims (FFS commercial / Medicare FFS): Each PICOTS element becomes code lists plus date logic. P and S jointly set the continuous-enrollment requirement (medical + pharmacy across the full T lookback) so that a "washout" reflects true absence of fills, not unobserved person-time. Failure mode: Medicare Advantage enrollees lack adjudicated FFS claims — utilization and outcomes are largely invisible — so MA-only person-time masquerades as a clean washout and as event-free follow-up; restrict to Parts A/B/D (or a commercial medical+pharmacy benefit) and exclude MA-only spans. I/C from NDC + `days_supply` (watch 90-day mail-order and free samples distorting episodes); procedures from CPT/ICD-10-PCS. Differential competing risks: in elderly claims cohorts, death competes with the outcome and may differ by exposure arm, so a T/O that ignores the competing event biases cumulative incidence — specify it in O, not just the model. - EHR: P and O can be sharpened with labs, vitals, staging, and notes (NLP), an advantage over claims for a narrow P. But capture is visit-driven: a patient who seeks care elsewhere is differentially lost, so T must define observation windows explicitly and treat loss to follow-up as potentially informative. I is the order/administration, not a dispensing — link to pharmacy fills to confirm the patient actually started, or a "new user" by order may never fill. - Registry: Cleanest for P (disease severity, stage) and adjudicated O (recurrence, death dates); typically weak for complete I/C utilization and exact timing. Link to claims for the full fill history and to a death index to firm up T (censoring). - Linked claims–EHR–vital records: The ideal substrate (EHR severity + claims completeness + reliable mortality), but linkage introduces selection (only the linkable subset, which may not match the target P) and order/fill/service date discrepancies that must be reconciled before T can assign a defensible time-zero.

Worked example (oncology new-user cohort, claims logic)

P: adults ≥18 with incident advanced NSCLC, no systemic anticancer fill or administration in a 12-month lookback (= incident/first-line), and 365 days of continuous medical + pharmacy, FFS-observable enrollment before index. I: initiate pembrolizumab + pemetrexed — defined by NDC/HCPCS J-codes; index_date = the first administration/fill of the regimen after the qualifying NSCLC diagnosis. C: initiate a platinum doublet (regimen code list), same eligibility and the same time-zero rule applied identically. O: overall survival (death from any cause via discharge status + a linked mortality index; a non-fatal claims-only proxy is insufficient for OS). T: time-zero at regimen initiation; a 30-day induction excludes events plausibly present before treatment could act; follow until death, disenrollment, end of data, or 36 months; for an as-treated contrast, censor at a switch or at last `days_supply` end + a pre-specified 90-day grace, with inverse-probability-of-censoring weights because discontinuation is likely differential by arm; specify death as a competing event for any non-mortality secondary endpoint. S: US commercial + Medicare FFS claims (e.g., Optum/MarketScan-style), 2018–2023, mortality-linked, MA-only person-time excluded, analyzed as a new-user active-comparator cohort with target-trial-emulation structure. The same six rows, ported to a distributed network (Sentinel/PCORnet via OMOP), keep the question fixed while each site re-maps the code lists and re-checks enrollment semantics — which is exactly the reproducibility PICOTS exists to buy.

Worked example

Scenario

A health outcomes team at a pharmacy benefit manager wants to know whether adults with type 2 diabetes who start a GLP-1 receptor agonist have fewer hospitalizations for heart failure over the following year compared with adults who start a DPP-4 inhibitor. Before pulling any data, the team fills in a PICOTS table to make sure every decision is written down and agreed upon. The table below shows each element and the specific answer the team records.

Dataset

PICOTS table: each row is one element of the framework, filled in for the heart-failure hospitalization question.

ElementLetterWhat it decidesThe team's answer
PopulationPWho is eligibleAdults age 18 or older with a type 2 diabetes diagnosis, enrolled continuously in commercial insurance for at least 12 months before starting either drug, with no prior use of either drug class in that 12-month look-back period
InterventionIThe treatment being evaluatedFirst prescription fill of any GLP-1 receptor agonist (semaglutide, liraglutide, dulaglutide, or exenatide); the date of that fill is the study start date for the patient
ComparatorCWhat the intervention is compared againstFirst prescription fill of any DPP-4 inhibitor (sitagliptin, saxagliptin, or alogliptin) on or after the same eligibility rules; matched to the GLP-1 group by the same study-start-date rule
OutcomeOThe event being countedA hospitalization with a primary discharge diagnosis code for heart failure, occurring any time after the study start date and before follow-up ends
TimingTAll clock and window decisions12-month look-back before start date to confirm no prior use; follow patients from start date until first heart-failure hospitalization, insurance disenrollment, death, or 12 months elapsed, whichever comes first; no induction delay because the effect is not expected to require months to appear
SettingSData source and study designUS commercial insurance claims database, calendar years 2019 through 2023; new-user active-comparator cohort design; patients in Medicare Advantage plans excluded because their hospitalization records are incomplete in this database

Steps

  • Start with P: the team writes down the diagnosis code, the age cutoff, the 12-month continuous enrollment requirement, and the requirement that neither drug was used before. This single row will become the eligibility query in the database.

  • Fill in I: the team lists the four specific drug names that count as GLP-1 receptor agonists and declares that the date of the first fill is the patient's study start date. Without this, two analysts might pick different drugs or different date rules and produce different cohorts.

  • Fill in C: the team picks DPP-4 inhibitors as the comparator because both drug classes treat type 2 diabetes and are prescribed to similar patients — this means differences in heart-failure rates are more likely to reflect the drug effect than background differences in patient health.

  • Fill in O: the team specifies that only hospitalizations with heart failure as the primary reason count. A patient admitted for pneumonia who also happens to have heart failure would not count, so the rule must be written down precisely.

  • Fill in T: the team sets the maximum follow-up at 12 months and lists every reason a patient stops being counted (first event, disenrollment, death, or the 12-month cap). This row will directly control how person-time is calculated in the analysis.

  • Fill in S: the team names the specific database, the calendar years, and the design. They also note the Medicare Advantage exclusion because that population's hospitalization data are incomplete, which would make the outcome look artificially rare.

  • Read the completed table back as one sentence to confirm the question is fully specified: Among adults 18 or older with type 2 diabetes, no prior use of either drug class, and at least 12 months of continuous commercial insurance coverage, does starting a GLP-1 receptor agonist versus starting a DPP-4 inhibitor reduce the rate of heart-failure hospitalizations over the following 12 months, measured in US commercial claims from 2019 to 2023 using a new-user active-comparator cohort design?

Result

The fully framed research question is: Among commercially insured adults age 18 or older with type 2 diabetes and no prior GLP-1 or DPP-4 use in the preceding 12 months, does initiating a GLP-1 receptor agonist reduce 12-month heart-failure hospitalization rates compared with initiating a DPP-4 inhibitor, evaluated in US commercial claims (2019-2023) with a new-user active-comparator cohort design? Every word in that sentence traces back to a specific row in the PICOTS table, so any reviewer can see exactly which decision produced each word — and flag any box they disagree with before analysis begins.

Runnable example

python implementation

A PICOTS specification template, not an analysis. It is the structured artifact a protocol author fills in BEFORE writing any extraction code, so that every downstream rule (eligibility SQL, exposure/outcome algorithms, time-zero, censoring) traces back to...

from dataclasses import dataclass, field

@dataclass
class PICOTS:
    # P — cohort + lookback/washout. Drives the eligibility query and continuous-enrollment rule.
    population: str            # e.g. "adults >=18, incident advanced NSCLC (>=1 inpatient or >=2 outpatient ICD-10 C34.* >=30d apart)"
    lookback_days: int         # disease/exposure-free lookback that defines 'incident'; e.g. 365
    enrollment_rule: str       # e.g. "continuous medical+pharmacy FFS A/B/D across [index_date-lookback, index_date]; exclude MA-only spans"

    # I / C — exposure and comparator strategies. Become NDC/HCPCS/CPT code lists + the time-zero rule.
    intervention: str          # e.g. "first administration of pembrolizumab+pemetrexed (HCPCS J9271 + J9305) after NSCLC dx"
    comparator: str            # e.g. "first administration of a platinum doublet (regimen code list); same time-zero rule"
    index_date_rule: str       # e.g. "index_date = first qualifying fill/administration; assign arm from that claim"

    # O — endpoint + validated algorithm + competing events.
    outcome: str               # e.g. "overall survival (death any cause)"
    outcome_algorithm: str     # e.g. "discharge status + linked national mortality index; claims-only proxy insufficient for OS"
    competing_events: str = "" # e.g. "death is a competing event for any non-mortality secondary endpoint"

    # T — every clock decision. The most under-specified PICOTS element in RWE.
    induction_days: int = 0    # exclude events in [index_date, index_date+induction_days)
    grace_days: int = 0        # allowable gap before an as-treated episode is considered ended (days_supply end + grace)
    max_followup_days: int = 0 # administrative cap; 0 = until disenroll/death/end-of-data
    censoring_rule: str = ""   # e.g. "censor at disenrollment, death, end of data, switch, or discontinuation+grace (apply IPCW)"

    # S — data source(s), design, calendar window, geography.
    setting: str = ""          # e.g. "US commercial + Medicare FFS claims, mortality-linked, 2018-2023, MA-only excluded"
    design: str = ""           # e.g. "new-user active-comparator cohort with target-trial-emulation structure"
    databases: list = field(default_factory=list)  # e.g. ["MarketScan-style commercial", "Medicare FFS"]

    def validate(self) -> list[str]:
        """Gate the protocol: every element must be filled, and T/S must be internally consistent."""
        problems = []
        for fld in ("population", "enrollment_rule", "intervention", "comparator",
                    "index_date_rule", "outcome", "outcome_algorithm", "setting", "design"):
            if not str(getattr(self, fld)).strip():
                problems.append(f"PICOTS '{fld}' is unspecified — resolve before building the cohort.")
        if self.lookback_days <= 0:
            problems.append("Timing: lookback_days must define the incident/washout window.")
        if self.max_followup_days and self.max_followup_days > 730 and "commercial" in self.setting.lower():
            problems.append("Timing/Setting mismatch: follow-up exceeds typical commercial enrollment "
                            "(~2y) -> differential administrative censoring risk.")
        if not self.censoring_rule.strip():
            problems.append("Timing: censoring_rule unspecified -> undefined person-time and estimand.")
        return problems