logo
Updated

Log Todoist Completed Tasks into Reflect through IFTTT

NEW VERSIÓN AVAILABLE: FIND IT HERE.

1. The basics

This automation requires an IFTTT Pro+ plan to use queries and filter codes. IFTTT has tripled the price of this plan since I started paying for it. I'm still paying the old pricing, hopefully this is your case too. If you know an alternative with a reasonable price for personal use let me know.

When a task is completed in Todoist it will be appended to today's daily note under the list ☑️ Tasks, along with its link, project, project section, description, and labels. Update 16/08/2024: I no longer append the tasks to a list; instead, I add a backlink at the beginning of each task. Also I don't import sections nor projects anymore. Read more in the last section.

Usually it takes up to 5 minutes for a completed task to show in Reflect. IFTTT explained that "The Todoist service uses polling triggers, which means IFTTT queries their API every 5 minutes to check for new trigger events."

Existing comments for each task will be logged too. If you're not interested in logging the comments, I'll tell you how to simplify the automation in the last section.

2. How your tasks will look in Reflect

Here is how your completed tasks will appear in your daily notes. In the descriptions and comments, you can find why I format the tasks this way:

☑️ Tasks

Another task with a description but no section nor labels . Note that a task always has a project in Todoist, even if it's just "Inbox". The rest of the metadata (description, section, and labels) is optional. 🚀 An incredible project > Project section.

A task with three comments . ✏️ A stupid project. 🚶‍♂️LabelErrand.

16/4/2024. This is a comment posted in this task and backlinked to the daily note of the date in which it was posted.

16/4/2024. I use comments to report updates on projects like progress, delays or new dependencies. Unless it's truly an independent task, I use parent tasks to group actionable tasks into small goals. I only add comments to these parent tasks, never to subtasks, to easily keep track of these updates from a single view. This way, I also get in Reflect a nice brief of how I managed it once is completed. Take into account that child tasks are independent and will be added to the daily note on the date are completed.

[[19/04/2024. Backlinks to daily notes are not supported by Reflect's API as of June 7, 2024. My workaround is to only add the two open brackets, so I just need to position the mouse at the end of the date to quickly create the backlink.

This task contains a link in its name . The linked arrow is the link to the completed task in Todoist. In my first versions of the applet the entire task name was the link to the task, but any external link in the name would break it. Also it was a bit distracting having such long links. 🚀 An incredible project. 🚶‍♂️LabelErrand.

Another task with three comments about task formatting . ✏️ A stupid project. 🏠LabelHome.

25/5/2024. You might wonder why I add Todoist labels as backlinks and not as tags. Tags in Reflect allow filtering entire notes but not parts of them. Only backlinks will create a clean list of the completed tasks within the backlinks section of the note of each tag. The same applies for projects and sections.

7/6/2024. Creating tasks though the API was not supported when I started building this automation, but it is since March 2024. Although, I still prefer to log my tasks as simple lists easy to read and not greyed. If you prefer to log them as Reflect tasks I explain how later.

2/6/2024 Comments may have links and lists. Lists in comments will be properly indented:

First item of a list in a comment.

Second item of the list.

Third item.

3 How to recreate the automation on IFTTT

IFTTT doesn't allow sharing applets with webhooks, so you will have to recreate them following this guide.

The automation consists of two applets, as it's the only way to save both the essential data of the task as well as its comments. In the future it may be possible to combine both applets into one, but for that IFTTT must add the task ID as an ingredient of the "New Completed Task" trigger, something it doesn't provide today. You can send them a feature request as I did.

This is what each applet does:

Applet 1: Triggered when a task is completed in Todoist, it will parse all the data of the task as a markdown formatted text. It will also extract the task ID by parsing the task link. It will send the formatted text and task ID to the second applet.

Applet 2: Triggered by the first applet. It will retrieve the comments of the task calling the Todoist API with the task ID. Later it will format the comments into a markdown list along with the previously formatted information of the task. Then it will call Reflect's API to append the result to today's daily note.

If you don't use Todoist comments you will only need the first applet, check the last section of this guide to know how to adapt it. Otherwise continue reading.

We will start creating the second applet, as we will need its webhook URL for the first one.

How to create the second applet

In If this choose the service Webhooks. IFTTT provides two types of webhooks that can be easily confused and both are used along the automation. Pay attention which one must be used in each step. Here select the trigger Receive a web request. As Event Name insert todoist2reflect or really any other you prefer.

Add a query to the applet. Choose the service Webhooks and the query Make a web request with JSON response. Complete the fields:

URL: https://api.todoist.com/rest/v2/comments?task_id= {{Value1}}

Yes, there is an space in = { ask IFTTT why 🤷.

Additional headers: Authorization: Bearer API_TOKEN

Replace API_TOKEN with your Todoist's API token found in Settings > Integrations > Developer tab.

Method: GET

Content type: application/json

Add a Filter code to the applet after the query. Paste this javascript:

// Extract the task information from the first IFTTT applet
let task: any = MakerWebhooks.event.Value2;

// Retrieve and parse comments
let comments: any = MakerWebhooks.makeWebRequestQueryJson[0].ResponseBody;
let parsedComments: any[] = JSON.parse(comments);

// Initialize formattedComments to ensure it's defined even if there are no comments
let formattedComments: string = '';

// Format the comments if there are any
if (parsedComments.length > 0) {
  formattedComments = parsedComments
    .map((comment: any) => {
      const date = new Date(comment.posted_at);
      // Ensure the month and day always have two digits
      const formattedDate = `[[${('0' + date.getDate()).slice(-2)}/${
        ('0' + (date.getMonth() + 1)).slice(-2)
      }/${date.getFullYear()}`; // Note: Closing brackets omitted until Reflect supports backlinks to daily notes from API
      const contentLines = comment.content.split('\n');
      const indentedContent = contentLines
        .map((line: string, index: number) =>
          index === 0 ? line : `\t${line}`
        )
        .join('\n');
      return `- ${formattedDate}. ${indentedContent}`;
    })
    .join('\n');
}

// Format body of the request
let body_request = JSON.stringify({
  text: `${task}\n${formattedComments}`,
  transform_type: 'list-append',
  list_name: '[[☑️ Tasks]]',
});

// Set body of the webhook
MakerWebhooks.makeWebRequest.setBody(body_request);

Back to the Edit screen of the applet select Then, choose the service Webhooks and the action Make a web request. Complete the fields:

URL: https://reflect.app/api/graphs/GRAPH_ID/daily-notes

Replace GRAPH_ID with your Reflect's graph identifier found in Preferences > Graphs.

Method: PUT

Content type: application/json

Additional headers: Authorization: Bearer ACCESS_TOKEN.

Replace ACCESS_TOKEN with a Reflect's access token. They can be created here.

Back again to the Edit screen, the applet should look like this:

Click Continue to save and name the applet to your preference. I use "Todoist Completed Task to Reflect - Step 2".

Copy the webhook URL from the details section of the applet and keep it somewhere, you will need it in the next steps.

How to create the first applet

In If this choose the Todoist service and New completed task as trigger. Connect your Todoist account to IFTTT if you haven't done already. Let the option Project to watch as Any project.

Add a filter code to the applet and paste this javascript:

// Extract task ID from URL
let taskIdMatch = Todoist.newCompletedTask.LinkToTask.match(/task\/(\d+)/);
let taskId = taskIdMatch ? taskIdMatch[1] : '';

// Format name and task link
let linkText: string = `${Todoist.newCompletedTask.TaskContent} [↗](${Todoist.newCompletedTask.LinkToTask})`;

// Format project as backlink (project is always present)
let project: string = `[[${Todoist.newCompletedTask.Project.trim()}]]`;

// Format section as backlink, if any
let section: string = Todoist.newCompletedTask.Section
  ? ` > [[${Todoist.newCompletedTask.Section.trim()}]]`
  : '';

// Format description, if any
let description: string = Todoist.newCompletedTask.TaskDescription
  ? `. ${Todoist.newCompletedTask.TaskDescription.trim()}`
  : '';

// Format labels as backlinks, if any
let labels: string = Todoist.newCompletedTask.Labels
  ? ` ${Todoist.newCompletedTask.Labels.split(',')
      .map((label) => `[[${label.trim()}]]`)
      .join(' ')}.`
  : '';

// Compound text
let content = `${linkText}${description}. ${project}${section}.${labels}`;

// Send task ID and task content to the second applet
MakerWebhooks.makeWebRequest.setBody(
  JSON.stringify({ value1: taskId, value2: content })
);

Back to the Edit screen select Then, choose the service Webhook and Make a web request as action. Complete the fields:

URL: paste the webhook URL of the first applet.

Method: POST

Content type: application/json

Back again to the Edit screen, tis first applet should look like this:

Click Continue to save and name the applet to your preference. I use "Todoist Completed Task to Reflect - Step 1".

First steps checking the automation and possible issues

Create and complete a few tasks with different combinations of labels, projects, comments, and descriptions and wait up to 20 minutes for them to show in the daily note. If nothing happens, ensure both applets are connected and check their activity to try to understand what’s happening. You can do so by selecting View activity on the main screen of each applet.

"Wait, up to 20 minutes? You said 5!" If you check the activity view of the first applet, it might soon get filled with "Trigger failed" notifications with a generic "There was a problem with the trigger". IFTTT support explained to me that these "trigger failures are mainly occurring due to timeouts from the Todoist API, meaning it took longer than 8000 milliseconds to respond to our trigger check". I requested them to at least change the generic error to a more specific one. IFTTT will keep trying to retrieve the completed tasks, but this might take a while until the Todoist API responds again.

Sometimes, after reconnecting the applet, IFTTT sent me all the tasks that were ever processed by the applet. When this happens, a crazy long list of tasks arrives in my daily note. I reported the bug to IFTTT and apparently they fixed it, but it happened to me again later. Tell me in Discord if you experience the same issue.

4. Nine ways to tune the automation to your liking

Idea 1. Log only tasks without comments

This just requires the first applet. Apply these two changes to the previous instructions:

Replace the last four lines of the filter code with this:

// Set body of the webhook
MakerWebhooks.makeWebRequest.setBody(content);

You can also remove the first three lines of the code that parse the task ID, as are not needed in this scenario.

In Then, fill the fields of Make a web request like this:

URL: https://reflect.app/api/graphs/GRAPH_ID/daily-notes

Method: PUT

Content type: application/json

Additional headers: Authorization: Bearer ACCESS_TOKEN.

Idea 2. Log them as completed Reflect tasks instead of as a bullet list

Change line 6 of the filter code of the 1st applet to prepend + [x] in the value of the string like this:

let linkText: string = `+ [x] ${Todoist.newCompletedTask.TaskContent} [↗](${Todoist.newCompletedTask.LinkToTask})`;

Idea 3. Log Todoist labels as Reflect hashtags

Change line 24 of the filter code of the 1st applet to remove the four brackets and add a hashtag like this:

      .map((label) => `#${label.trim()}`)

Idea 4. Group tasks by project

While creating the first applet, after choosing the New completed tasks trigger, instead of selecting Any project in the Project to watch choose a particular project and later change the name of the parent list as described above to match the project name.

You will need to create as many applets as projects you want to log. Keep the second applet untouched as it will keep adding the comments to all the tasks retrieved by these applets.

Idea 5. Append the tasks independently without being under the ☑️ Tasks list

Remove this line in the filter code of the second applet:

  list_name: '[[☑️ Tasks]]', 

Optional but recommended to keep collecting all the tasks in the backlinks section of a note:

Add a shorter alias to the note ☑️ Tasks letting the title like this: ☑️ Tasks // ☑️

Change this line in the filter code of the first applet to add the checkbox ☑️ backlinked to that note at the beginning of each task.

let linkText: string = `[[☑️]] ${Todoist.newCompletedTask.TaskContent} [↗]

This way a task will look like this:

☑️ Name of the task . Description of the task. 🚀 An incredible project.🚶‍♂️LabelErrand.

Idea 6. Simplify by skipping sections and projects

Recently, I started using a personal mix of Carl Pullein's and Naomi's Todoist setups. Importing sections and projects has no utility with this setup. I use labels to refer to a project. Ignore projects and sections by removing these lines in the filter code of the first applet:

// Format project as backlink (project is always present)
let project: string = `[[${Todoist.newCompletedTask.Project.trim()}]]`;

// Format section as backlink, if any
let section: string = Todoist.newCompletedTask.Section
  ? ` > [[${Todoist.newCompletedTask.Section.trim()}]]`
  : '';

Other ideas

7. Arrange the information of the tasks in other way. Change line 29 of the filter code of the 1st apple.

8. Change the name of the parent list. Indeed mine is ☑️ Tareas in Spanish. Change line 35 of the filter code of the 2nd applet.

9. Change the separator between elements. After several iterations I realized a simple dot made the tasks easier to read and less distracting than other separators, considering backlinks already offer a good visual indication. You may prefer other options like a slash /, a vertical bar | or an em dash . To do so, replace the dots inside the strings of lines 18, 25 and 29 of the filter code of the 1st applet.