How to Create Real Recurring Location-based iOS Reminders

Inexplicably, iOS Reminders do not have a repeat option underneath their “Remind me at a location” setting when creating a reminder, or a “Remind me next time” (…I arrive here) selection when you hard-press a reminder notification.  The only way to hackily get repeated location-based reminders is to never mark them as completed.  The problem with that way of dealing with location-based reminders is that 1. they eventually disappear from your notifications and 2. you cannot tell whether you’ve actually completed the reminded task or it is still yet to be done.

I have figured out a way to create recurring location-based reminders using:

  1. iCloud synchronized Reminders
  2. IFTTT
  3. Dropbox
  4. Folder action on an always-on computer

Read on to learn how…

There are a few caveats.

First, location-based reminders never show as “due”, even after the triggering arrival/left event has occurred, so they never appear as “overdue”.  They will simply show up as a notification and eventually disappear a few hours later.  You can dismiss their notification in one of a few ways:

  1. Ignore (I’m not actually sure how this affects future geofence triggerings, but you will have no way to discern undone items from completed ones once they have been ignored)
  2. Mark as completed (which turns off all future location-based triggerings)
  3. Remind me in… (adds a date/time-based reminder)

This solution allows you to keep the notification in notification center either until the notification expires or until it is marked as done.  If it is not marked as done, it will trigger again the next time the geofence boundary is crossed.  If it is marked as done, the IFTTT rule we create will (within a few hours) mark the reminder as not complete and it will not be re-added to notification center until the geofence boundary event occurs again.

The second caveat is that you must maintain a separate reminder list exclusively for recurring location based reminders.

The third caveat is that you need to have a computer with dropbox that either is always running or is guaranteed to be turned on and sync with dropbox between the geofence triggering events.  Folder actions must be enabled and the permissions must allow Automator the access your reminders.

Fourth, you must sync your reminders on both your computer and any iOS devices in which you use the iOS Reminders app.

Here’s how to do it.

  1. In your Reminders app from either your iCloud-reminder-synched iOS device or your computer, create a new list with a unique name
  2. On a mac computer that you always keep running, create a folder somewhere in your ~/Dropbox folder that you will only use via the IFTTT applet we will create later. (I have a ~/Dropbox/IFTTT/FolderActions folder in which I create folder actions folders).
  3. Open /Applications/ and create a new document of type “Folder Action”
  4. Select the folder created in step 2 from the “Folder Action receives files and folders added to” menu at the top of the workflow. (You may need to enable folder actions by right-clicking the folder in the Finder and looking under the “Services” submenu of the contextual menu that appears.)
  5. In Automator, drag the “Run Applescript” action to the workflow’s workspaceautomatorapplescript
  6. Replace the script text with the following code (click the image to get to the copyable code): recurgeorem.png
  7. Be sure to replace the value of myList (Reminder list name from step 1) in the code with the name of your list created in step 1.
  8. Save the Automator workflow.
  9. Next, we must test the workflow in order to address permissions issues that you should be prompted about the first time the folder action runs.
    1. Create a “test” reminder in the reminder list created in step 1 (it doesn’t need to have a location-based reminder)
    2. Mark the new reminder as completed (and optionally select to show completed)
    3. Open Text and create a new file
    4. Enter “test” (without quotes) into the file
    5. Select Format->Make plain text (unless the document is already plain text, in which case, that menu item will not be there)
    6. Save the file inside the folder created in step 2
    7. Within a few seconds, you should be prompted to allow access from automator (i.e. folder actions) to your reminders
    8. Then repeat the test by duplicating the file in the Finder (you can quit text edit)
    9. Trouble-shoot any issues that arise
  10. Create an IFTTT applet with the following parameters (this assumes you have the Dropbox and iOS Reminders services enabled):
    • This: iOS Reminders “Reminder completed in list”
    • That: Dropbox “Create a text file”
    • Settings:
      • List: The list name created in step 1
      • File name: “{{Title}}”
      • Content: “{{Title}}”
      • Dropbox Folder Path (starting after ~/Dropbox/): based on the folder created in step 1 – (example) “IFTTT/georeminders”
    • The end result settings will look something like this: georemsifttt.png
  11. Save the IFTTT applet and give it a memorable name.

And that’s it.  From now on, when you complete a location-based reminder in the list you created, it will be reset (within a few hours according to IFTTT) so that the next time you arrive/leave the configured location in the reminder, it will notify you again.  And you can safely mark the item as completed each time so that you don’t have to keep it appearing in notification center.

Be sure that the “{{Title}}” ingredient in the IFTTT applet sits on the first line without any extraneous spaces or characters, because that first line must exactly match the reminder title in the Reminders app.

A couple tips.  Whenever I create a folder action that is controlled by IFTTT or elsewhere, I usually add a README text file to the folder that links to the IFTTT applet and shows where the automator workflow can be found.  That way, if it stops working or you forgot how you set things up, you can look it up in the README.  You might even just link to this blog post.  To debug, you can also create a log file that is added to from the applescript, but that’s much more complex than I wanted this blog post to be.

You will have to clear out files from this folder manually on occasion, but they will be small, so it shouldn’t be necessary too often, unless you’re short on dropbox space.  You can also optionally add code to clean up after itself.

2 thoughts on “How to Create Real Recurring Location-based iOS Reminders

  1. iOS 13 broke the IFTTT/Reminders integration. I have a workaround that uses an AppleScript run via cron job:

    Look for newly completed reminders (since the last check) and if there is a new one, make a webhook post with date, title, and list JSON values
    by Robert W. Leach, based on scripts by Craig Eley, Samantha Hilton, and Nick Morris
    This is not foolproof. If you have more than 1 device you use to "complete" reminders and a reminder is completed while offline, after which, a reminder is completed from a second online device, the completion of the reminders in the offline device (once it comes online) will be missed. However, it's done this way so that the script doesn't take forever looking at all reminders each time.
    Schedule it to run as frequently as you would like using osascript in a cron job and forget about it. Run once manually in order to "allow" this script to run in the security settings by responding to the resulting dialog.
    Cron job every 30 minutes looking for newly completed reminders in list "MyReminders" example (execute `crontab -e` in terminal and enter): */30 * * * * osascript /Users/username/Scripts/completion_notifier.scpt "/Users/username/reminder_completions.txt" "" -1 "MyReminders"
    Run without command line arguments to get the usage
    Command line argument examples:
    "~/completed_reminders.txt" –No spaces allowed in file path. File does not need to pre-exist (but directories do).
    "{event}/with/key/{key}" –Empty = don't make a webhook call (for testing)
    -1 –Priority level cutoff. -1 = all. 1 = !, 2 = !!, 3 = !!!. Considers only reminders with priority greater than this value.
    "ToDo" –Empty = all. Example: "Grocery" "ToDo" "Work" "Home" – only provided lists are checked for newly completed items
    on run argv
    set debug to false
    if (count of argv) is less than 3 then
    return "Usage: osascript completion_notifier.scpt \"/path/to/outfile.txt\" \"http://webhook_url\" priority_level [reminder list names…]" & linefeed & "Example: osascript completion_notifier.scpt \"/Users/jsmith/completed_reminders.txt\" \"\" -1"
    end if
    set lastcompletionfile to item 1 of argv
    set webhookurl to item 2 of argv
    set prilev to item 3 of argv
    set liststocheck to {}
    if (count of argv) is equal to 4 then
    set liststocheck to {item 4 of argv}
    else if (count of argv) is greater than 3 then
    set liststocheck to {items 4 thru (count of argv) of argv}
    end if
    tell application "Reminders"
    set {startdate, firsttime} to my getStart(lastcompletionfile)
    if debug is true then
    display dialog "Starting datetime: " & startdate as text
    end if
    set output to ""
    set lastcompletion to startdate
    set mostrecentdate to ""
    set mostrecenttitle to ""
    set mostrecentlist to ""
    Find entries completed today from each list
    set hasOne to false
    repeat with alist in every list
    set mylist to name of alist as text
    if (count of liststocheck) is 0 or liststocheck contains mylist then
    set listid to id of alist as text
    if debug is true then
    display dialog mylist & linefeed & listid
    display dialog mylist
    end if
    repeat with reminderObj in (reminders in alist whose (completed is true) and (completion date is greater than startdate) and (priority is greater than prilev))
    set nameObj to name of reminderObj
    set compDateObj to completion date of reminderObj
    set timeStr to date string of compDateObj & " at " & time string of compDateObj
    set idObj to id of reminderObj
    if compDateObj is greater than lastcompletion then
    set hasOne to true
    set lastcompletion to compDateObj
    set mostrecentdate to timeStr
    set mostrecenttitle to nameObj
    set mostrecentlist to mylist
    end if
    if debug is true then
    display dialog idObj & tab & timeStr & tab & nameObj
    end if
    set output to output & listid & tab & idObj & tab & timeStr & tab & mylist & tab & nameObj & linefeed
    set output to output & timeStr & tab & mylist & tab & nameObj & linefeed
    if debug is true then
    display dialog listid & tab & idObj & tab & timeStr & tab & mylist & tab & nameObj
    display dialog timeStr & tab & mylist & tab & nameObj
    end if
    end repeat
    end if
    end repeat
    if hasOne is true then
    save the newly completed items found this time so that next time, we can look for newer items
    set shellTxt to "echo \"" & output & "\" > " & lastcompletionfile
    if debug is true then
    display dialog shellTxt
    end if
    do shell script shellTxt
    Make the webhook call (if the webhookurl is not an empty string)
    if webhookurl is not "" then
    Use this example to send json data
    set shellScript to "curl -X POST –data-urlencode 'payload={\"channel\": \"#general\", \"username\": \"Completion Notifier Bot\", \"icon_emoji\": \":ghost:\"}' " & webhookurl
    set jsonoption to "–data-urlencode 'payload={\"value1\": \"" & mostrecentdate & "\", \"value2\": \"" & mostrecenttitle & "\", \"value3\": \"" & mostrecentlist & "\"}'"
    set shellTxt to "curl -X POST " & jsonoption & " \"" & webhookurl & "\" > /dev/null"
    if debug is true then
    display dialog shellTxt
    end if
    do shell script shellTxt
    end if
    Save the date this was run so it can be parsed later the next time it's run
    if firsttime is true then
    set shellTxt to "echo \"" & startdate & tab & "initial run" & tab & "no completed reminders" & linefeed & "\" > " & lastcompletionfile
    if debug is true then
    display dialog shellTxt
    end if
    do shell script shellTxt
    end if
    if debug is true then
    display dialog "Nothing is newly completed"
    end if
    end if
    end tell
    end run
    Takes the file containing the last determined most recent completion date (since the last time this script ran).
    Returns from the file, the most recent reminder completion date and a boolean indicating whether write an initial start record into the file
    on getStart(lastcompletionfile)
    set startdate to the current date
    set checkscript to "if [ -e \"`eval echo " & lastcompletionfile & "`\" ]; then echo yes; else echo no; fi"
    display dialog checkscript
    set fileisthere to first paragraph of (do shell script checkscript)
    display dialog lastcompletionfile & " exists? [" & fileisthere & "]"
    set gotone to false
    if fileisthere is equal to "yes" then
    set lastdate to missing value
    set datescript to "cut -f 3 " & "\"`eval echo " & lastcompletionfile & "`\""
    display dialog datescript
    set datelines to paragraphs of (do shell script "cut -f 1 " & "\"`eval echo " & lastcompletionfile & "`\"")
    repeat with adateline in datelines
    display dialog "Checking [" & adateline & "]"
    set tmpdate to date adateline
    if lastdate is missing value or tmpdate is greater than lastdate then
    set lastdate to tmpdate
    set gotone to true
    display dialog "Later: " & lastdate as text
    end if
    end try
    end repeat
    if gotone is true then
    display dialog "Setting start date: " & lastdate as text
    set startdate to lastdate
    end if
    end if
    display dialog "Returning start date: " & startdate as text
    return {startdate, not gotone}
    end getStart

    More later…


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s