Two-way sync between Todoist and Obsidian

Sync your tasks from Obsidian to Todoist and sync their states in both directions with the Create Todoist tasks and sync state-command.


How to get the command

There are two ways to get the command in your Obsidian vault:

What it does

The Create Todoist tasks and sync state-command will check the currently active document for new to-dos and add them to Todoist.

You can mark them as done in either Obsidian or Todoist. The next time you run the command the states will be synced.

Tweaks you may consider

Link directly to the task instead of just the document

ℹ️ This only works, if you have the advanced-uri plugin installed.

These changes

  • will add a block id to every synced task
  • link directly to the block from the Todoist description, using the advanced URI

In the command settings set the description parameter to

[Link to Obsidian](obsidian://advanced-uri?vault={{ vaultName | url_encode }}&filepath={{ filePath | url_encode}}&block={{ task | hash | slice: 0, 5 }})

and the updateTemplate parameter to

{%- assign tasks = tasks | reverse -%}
{%- assign update = original -%}

{%- for task in tasks -%}

{%- comment -%}
This section checks if a task was added to Todoist for a to-do found in the text. It then adds the link to the task
{%- endcomment -%}

{%- assign addCommand = task.commands | where: "type", "item_add" | first -%}
{%- if addCommand -%}

{%- assign todoistId = idMap[addCommand.temp_id] -%}
{%- capture updatedLine %}{{ task.text.match | rstrip }} [Todoist]({{ todoistId }}) ^{{ task.text.match | hash | slice: 0, 5 }}{% endcapture -%}
{%- assign length = task.text.match | size -%}
{%- assign update = update | replaceAtPosition: updatedLine,  task.text.index, length -%}

{%- else -%}

{%- comment -%}
This section checks if a task was completed in Todoist and checks it off. The Todoist API is not very friendly in this case. So this is not very straight forward...
{%- endcomment -%}
{%- assign todoistId = task.todoist.todoistId -%}
{%- unless todoistId -%}
{%- assign  updatedLine = task.text.match | replace_first: "[ ]", "[x]" -%}
{%- assign update = update | replaceAtPosition: updatedLine,  task.text.index -%}
{%- endunless -%}

{%- endif -%}
{%- endfor -%}
{{ update }}

Common questions

How can I specify the project?

Add a data tag to your to-do line. Example: - [ ] this task has a project #project::projectname. This only works for projects without spaces in their name!

How can I specify the due date?

Add a data tag to your to-do line. Example: - [ ] this task has a due date #due::2024-12-31

How can I add labels?

Obsidian tags will be used as labels. Example: - [ ] this task needs some labels! #label1 #label2

How does Taskbone know what Todoist task an Obsidian task corresponds to?

After a task was created in Todoist, the Obsidian document will be updated and a link to the Todoist task will be added to the corresponding line. This link should not be changed, because it is used to link these items together.

How do I find the source document for a task in Todoist?

A link to the Obsidian document is added to the description of the Todoist task.

What changes are synced from Todoist to Obsidan?

Only the status will be synced back to Obsidian. Other changes will have no effect. If you delete a task in Todoist, it will be considered done.

What changes are synced from Obsidian to Todoist?

Only the status and hierarchy of tasks will be synced. If you convert a task into a child task or vice versa, this change will be reflected in Todoist after the next sync. Deleting a task in Obsidian has no effect on the Todoist task.

How can I reopen a task?

A “done”-state in one place always overwrites an “open”-state on the other side. To reopen a task, you need to reopen it everywhere before you sync again.