EMA: Random Schedule (Flexible)

ema
survey
scheduling
alert
repeating-events
api
Implementing flexible EMA sampling using repeating events, external schedule generation, and Alerts
Published

January 12, 2026

Overview

Problem: You need flexible EMA sampling where schedules are generated externally, can be adjusted after enrollment, and you want tight control over timing constraints without creating dozens of events or Automated Survey Invitations (ASIs).

Solution: Use a longitudinal project with repeating events, store delivery schedules in one instrument, collect responses in another, import schedules via the Data Import Tool or API, and send surveys using Alerts with [current-instance] piping.

Prerequisites

  • A longitudinal REDCap project
  • An email field for participants (or phone number for SMS)
  • Ability to generate schedules (R, Python, Excel, or similar)
  • Data Import Tool access OR API access
  • Project Setup and Design rights
  • Alerts & Notifications rights

When to Use This Approach

This approach works well when:

  • You need random or semi-random sampling with custom constraints
  • You want to adjust schedules after participant enrollment
  • You can generate schedules using external tools
  • You want fine control over sampling rules (minimum spacing, time-of-day constraints, etc.)
  • You want both fixed and random schedules to work the same way
  • You need to track which scheduled surveys were answered

See the EMA overview for other approaches.

Trade-offs

Advantages:

  • Maximum flexibility in scheduling logic
  • Can adjust schedules after enrollment (just re-import)
  • Easy to implement complex spacing rules
  • No need for many events or ASIs
  • Instance numbers link schedules to responses, making analysis straightforward

Drawbacks:

  • Requires external tools to generate schedules
  • Must manually implement reminders and expiration
  • Requires Data Import Tool or API access

Steps

Create the Project Structure

  • Create a longitudinal project with two events:
    • main: For enrollment and baseline data
    • ema: For the scheduled surveys
  • In the main event, add an instrument to collect the participant’s email address (or phone number for SMS):
    • Field Type: Text Box
    • Validation: Email (or Phone)
    • Variable Name: email
  • In Project Setup > Designate an email field for communications, select email

Create the Schedule Instrument

  • Create a new instrument called schedule with at least two fields:
    • deliver_at:
      • Field Type: Text Box
      • Validation: Datetime (Y-M-D H:M)
      • Variable Name: deliver_at
    • expires_at:
      • Field Type: Text Box
      • Validation: Datetime (Y-M-D H:M)
      • Variable Name: expires_at
  • These fields will be populated by data import or API, not by users
Note

If you have multiple data collection periods (e.g., pre- and post-intervention), it’s probably easiest to add an ema_period field to the schedule form and fill that in with your schedule generation script. The exception would be if you need the Alert text to be different, or if you’re collecting different data in your different EMA periods.

Create the EMA Survey Instrument

  • Create a new instrument called ema with your data collection fields
  • Add a started_at field to track when participants begin the survey:
    • Field Type: Text Box
    • Validation: Datetime (Y-M-D H:M)
    • Variable Name: started_at
    • Action Tags: @HIDDEN @NOW
  • Enable the instrument as a survey
  • Configure survey settings as desired

Configure the EMA Event as Repeating

  • Go to Project Setup > Repeating instruments and events
  • Click Enable
  • For the ema event, select Treat the entire event as repeating
  • Ensure both the schedule and ema instruments are designated for the ema event
Note

Instance numbers will now be synchronized across both instruments. Instance 1 of schedule corresponds to instance 1 of ema, and so on. This makes it easy to see which surveys were completed.

Generate and Import Schedules

  • Generate your schedules externally using R, Python, Excel, or similar tools. Each row should include:
    • record_id
    • redcap_event_name (the ema event’s unique name, typically ema_arm_1)
    • redcap_repeat_instance (1, 2, 3, …)
    • deliver_at (format: YYYY-MM-DD HH:MM)
    • expires_at (format: YYYY-MM-DD HH:MM)
  • Import the schedules using Data Import Tool or the API
Note

Schedule generation is left as an exercise for now.

Create the Alert to Send Surveys

  • Go to Alerts & Notifications
  • Click Add New Alert
  • Configure the Alert:
    • Alert title: Something like “Send EMA Survey”
    • Trigger alert when: (datediff("now", [ema_arm_1][expires_at][current-instance], "s", true) > 0)
      • The [current-instance] piping is critical — without it, the Alert will evaluate against all instances and send far too many notifications
      • The logic checks if “now” is before expires_at. If the alert is delayed for any reason (REDCap scheduler down, blank email field, bug in logic), expired surveys won’t be sent when the problem is fixed.
    • Ensure logic is still true before sending: Check this box
    • When to send the alert: At the time specified by a date/time field
      • Field: deliver_at
    • How often to send: Only once per event-instance in a record
    • Email To: [email]
    • Email Subject: Your survey invitation subject
    • Alert message: Include the survey link: [ema_arm_1][survey-url:ema][current-instance]
Warning

The [current-instance] piping is essential in both the trigger logic and the survey URL. Without it, the Alert will not work correctly.

(Optional) Add Reminders

If you want to send reminder notifications for incomplete surveys:

  • Modify the Alert trigger logic to include a check for whether the survey was started:
    • (datediff("now", [ema_arm_1][expires_at][current-instance], "s", true) > 0) and ([ema_arm_1][started_at][current-instance] = "")
  • This ensures reminders are only sent if the survey hasn’t been started yet

(Optional) Implement Survey Expiration

To hide survey questions after the expiration time:

  • On the ema instrument, add a calculated field to check if the survey has expired:
    • Field Type: Calculated Field
    • Variable Name: is_expired
    • Calculation: datediff([started_at], [expires_at], "s", true) > 0
  • Use branching logic on your data collection fields to hide them when [is_expired] = 1
  • Add a Descriptive Text field (or use a section header) with branching logic [is_expired] = 1 that displays an expiration message
Note

Multi-page surveys and section headings work well for creating a clean expiration experience.

Notes

  • Timing precision: How often REDCap checks scheduled Alerts depends on your server settings. Our server checks every 5 minutes. Send immediately Alerts are generally not subject to this delay.
  • Scheduled Alerts are sometimes absent: Between the time an Alert is scheduled and when it’s actually sent, it will not appear in the Alerts Log in either the past or future alerts.
  • Checking message delivery: The only way to check whether messages have been delivered is to use the Notification Log in Alerts & Notifications.
  • Rescheduling: You can regenerate schedules and re-import them to adjust survey times. A future recipe will cover rescheduling in detail.
  • Email and SMS: This approach works identically for both email and SMS (via Twilio, Mosio, or similar providers).
  • Stopping messages: To stop surveys for participants who withdraw, see Stopping Alerts and ASIs
  • Time zones: Time zones will
CautionDon’t forget: Download those Notificaiton logs!

The only way you can make sure your Alerts are being delivered is to download the Notification Log. Don’t forget to do this on a regular basis (and reconcile against what you think you are delivering) or you may realize you haven’t been collecting the data you think you have.

Traps

Warning

Changing the deliver_at times will not reschedule already-scheduled Alerts!

To reschedule, you need to toggle the Alert logic to temporarily be false, and then make it true again. One way to do this is to add a needs_rescheduling Yes/No field to the schedule form, import a 1, then import 0, and include and [ema_arm_1][needs_rescheduling][current-instance] <> 1 in the Alert logic.

This really deserves its own recipe.

Warning

Once an Alert has been sent, changing its schedule to the future will not re-schedule it. You’ll need to add a new instance.

Troubleshooting

Alerts aren’t sending

  • Verify the Alert is enabled and saved
  • Check that the trigger logic evaluates to true for the records you expect
  • Remember the 5-minute (or whatever your server uses) delay for scheduled Alerts
  • Check Alerts & Notifications > View Alerts Log to see what’s been sent

Too many Alerts are sending

  • Verify you’re using [current-instance] in the trigger logic

It can be helpful to schedule your alert timings at the same granularity as the server’s scheduler.

Alerts are sometimes missing from the logs

During the time between when an Alert’s scheduled time has passed and when it is sent, it will not appear in the Notification Log at all.

Import fails

  • Verify your event name matches REDCap’s unique event name (e.g., ema_arm_1)
  • Check that you’ve selected Allow creation of new records? in the Data Import Tool