

How to Broadcast Todoist Task Completions to Slack with n8n
When a task is marked complete in Todoist, n8n catches the webhook and posts a formatted announcement to a Slack channel within seconds.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Teams using Todoist for project tracking who want stakeholders to see completed work in Slack without anyone manually posting updates.
Not ideal for
Teams completing hundreds of tasks per day — the Slack channel will become noise; use a daily digest with Make instead.
Sync type
real-timeUse case type
notificationReal-World Example
A 12-person product agency tracks client deliverables in Todoist projects. Every time a designer or developer marks a task done, n8n posts to #project-wins in Slack with the task name, assignee, and project. Before this, the project manager spent 20 minutes each morning manually updating the team on what shipped yesterday — now they see it as it happens.
What Will This Cost?
Drag the slider to your expected monthly volume.
Each platform counts differently — Zapier: 1 task per trigger. Make: 1 operation per module per record. n8n: 1 execution per run.





Prices shown for annual billing. Based on published pricing as of April 2026.
Estimated ROI
1000
min saved/mo
$583
labor value/mo
Free
no platform cost
Based on ~2 min manual effort per operation at $35/hr fully loaded labor cost.
Implementation
Import this workflow directly into n8n
Copy the pre-built n8n blueprint and paste it straight into n8n. All modules, filters, and field mappings are already configured — you just need to connect your accounts.
Before You Start
Make sure you have everything ready.
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Task Name | event_data.content | |
| Completed At | event_data.completed_at | |
| Project ID | event_data.project_id | |
| Slack Channel | ||
| Slack Message Text | ||
4 optional fields▸ show
| Task Description / Notes | event_data.description |
| Completer User ID | event_data.user_id |
| Task Priority | event_data.priority |
| Due Date | event_data.due.date |
Step-by-Step Setup
n8n Canvas > New Workflow
Create a new n8n workflow
Log into your n8n instance and click the orange 'New Workflow' button in the top right of the canvas. Give it a clear name like 'Todoist → Slack Task Broadcast'. You'll land on a blank canvas with a single grey node labeled 'Start'. You won't use that Start node — you're replacing it with a webhook trigger.
- 1Click 'New Workflow' in the top-right corner
- 2Click the workflow title at the top and rename it to 'Todoist → Slack Task Broadcast'
- 3Click the grey 'Start' node and press the Delete key to remove it
Canvas > + > Webhook
Add a Webhook trigger node
Click the '+' button in the center of the empty canvas to open the node selector. Search for 'Webhook' and select it. In the right panel, set the HTTP Method to POST and note the webhook URL shown — you'll paste this into Todoist in the next step. Set Authentication to 'None' for now (Todoist sends a secret token you can validate later in a code node).
- 1Click the '+' icon on the empty canvas
- 2Type 'Webhook' in the search bar and select the Webhook node
- 3Set HTTP Method to 'POST'
- 4Copy the 'Test URL' shown in the node panel — you'll need it in Todoist
Todoist Web App > Settings > Integrations > Developer
Register the webhook in Todoist
Todoist doesn't expose webhook settings in its main UI — you register webhooks via their REST API. Open a terminal or use a tool like Postman. You need your Todoist API token from Settings > Integrations > Developer in the Todoist web app. Send a POST request to https://api.todoist.com/sync/v9/webhooks with your token and the n8n webhook URL. Subscribe only to the 'item:completed' event to avoid flooding n8n with unrelated triggers.
- 1In Todoist, go to Settings > Integrations > Developer and copy your API token
- 2Open Postman (or curl in a terminal)
- 3POST to https://api.todoist.com/sync/v9/webhooks with header Authorization: Bearer YOUR_TOKEN
- 4Set the request body: { "url": "YOUR_N8N_WEBHOOK_URL", "events": ["item:completed"] }
- 5Confirm the response returns a webhook ID — save it if you need to delete this webhook later
n8n Canvas > Webhook Node > Test Workflow
Capture a test event from Todoist
Back in n8n, click 'Test Workflow' so the Webhook node starts listening. Switch to Todoist and complete any task in any project. Within 2-3 seconds, n8n should receive the event and display the raw payload in the Webhook node's output panel. Expand the data to see the fields Todoist sends — you need content (task name), completed_at, project_id, and user_id.
- 1Click 'Test Workflow' at the top of the n8n canvas
- 2Switch to Todoist in another tab
- 3Mark any task as complete by clicking the circle next to it
- 4Switch back to n8n and click on the Webhook node to see the incoming data
Canvas > + > Code
Add a Code node to format the message
Click the '+' after the Webhook node and add a 'Code' node. This is where you build the Slack message string from the raw Todoist payload. The Todoist webhook body is nested — the task data lives inside event_data, not at the top level. Write a short JavaScript snippet to extract task name, project ID, and completion time, then format them into a readable Slack message string. See the Pro Tip section for the full code.
- 1Click '+' after the Webhook node
- 2Search for 'Code' and select the Code node
- 3Set the language to JavaScript
- 4Paste the transformation code from the Pro Tip section below
- 5Click 'Execute Node' to verify the output shows a formatted message string
Paste this into the first Code node (Step 5). It extracts and normalizes all task fields from Todoist's nested webhook payload, formats the timestamp into human-readable UTC, adds an urgency emoji for priority-4 tasks, and guards against the Todoist verification ping — saving you a separate IF node.
JavaScript — Code Node// n8n Code Node — Todoist Task Completion Parser▸ Show code
// n8n Code Node — Todoist Task Completion Parser // Paste into the first Code node after the Webhook trigger const payload = items[0].json;
... expand to see full code
// n8n Code Node — Todoist Task Completion Parser
// Paste into the first Code node after the Webhook trigger
const payload = items[0].json;
// Guard against Todoist's webhook verification ping
if (!payload.event_data) {
return [];
}
const task = payload.event_data;
// Extract core fields
const taskName = task.content || 'Unnamed Task';
const projectId = task.project_id ? task.project_id.toString() : null;
const userId = task.user_id ? task.user_id.toString() : null;
const priority = task.priority || 1; // 1=normal, 2=medium, 3=high, 4=urgent
const description = task.description || '';
const dueDate = task.due ? task.due.date : null;
// Format completion timestamp
const rawTimestamp = task.completed_at || new Date().toISOString();
const completedDate = new Date(rawTimestamp);
const formattedTime = completedDate.toLocaleString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZone: 'UTC',
timeZoneName: 'short'
});
// Determine urgency emoji based on Todoist priority
const priorityEmoji = priority === 4 ? '🔥✅' : '✅';
// Check if task was completed after its due date
let lateFlag = '';
if (dueDate) {
const due = new Date(dueDate);
if (completedDate > due) {
lateFlag = ' _(completed late)_';
}
}
// Build partial message — project name gets added in the merge Code node (Step 7)
const partialMessage = `${priorityEmoji} *${taskName}* has been completed!${lateFlag}`;
return [
{
json: {
taskName,
projectId,
userId,
priority,
description,
formattedTime,
partialMessage,
rawTimestamp
}
}
];channel: {{channel}}
ts: {{ts}}
Canvas > + > HTTP Request
Look up the project name via Todoist API
Add an HTTP Request node after the Code node. Configure it to GET https://api.todoist.com/rest/v2/projects/{{ $json.project_id }} using the Todoist API token in a Bearer Authorization header. This returns the project name so your Slack message reads 'Website Redesign' instead of '2316456789'. Store this result — the next node will merge it with the formatted message.
- 1Click '+' after the Code node and add an 'HTTP Request' node
- 2Set Method to GET
- 3Set URL to https://api.todoist.com/rest/v2/projects/{{ $('Code').item.json.project_id }}
- 4Add a header: Authorization = Bearer YOUR_TODOIST_API_TOKEN
- 5Click 'Execute Node' to confirm it returns a name field with the project name
Canvas > + > Code
Merge task data and project name
Add another Code node after the HTTP Request node. Here you combine the formatted message from step 5 with the project name from step 6 to produce the final Slack message. Reference the previous nodes using n8n's $('NodeName').item.json syntax. Build the final message string with emoji, bold task name (using Slack's mrkdwn format), and the resolved project name.
- 1Click '+' after the HTTP Request node and add a second Code node
- 2Name it 'Build Final Message' for clarity
- 3Reference the task name from the first Code node using $('Code').item.json.taskName
- 4Reference the project name using $('HTTP Request').item.json.name
- 5Output a single object with a slackMessage field
Canvas > + > Slack > Send a Message
Add the Slack node and connect your workspace
Click '+' after the merge Code node and search for 'Slack'. Select the Slack node and choose 'Send a Message' as the operation. Click 'Create New Credential' and authenticate via OAuth2 — this opens Slack's authorization screen where you'll approve the connection. You need the channels:write and chat:write OAuth scopes granted. n8n will store the token after you approve.
- 1Click '+' after the second Code node
- 2Search for 'Slack' and select the Slack node
- 3Set Operation to 'Send a Message'
- 4Click 'Credential for Slack API' > 'Create New'
- 5Complete the OAuth flow in the popup window and click Allow
Slack Node > Parameters > Channel + Message
Configure the Slack message destination and body
In the Slack node, set Channel to the channel where completed tasks should broadcast — type the channel name like #project-wins. For the message text, reference the slackMessage field from your merge Code node using the expression {{ $json.slackMessage }}. Enable 'Use Blocks' only if you want richer formatting — for most teams, plain mrkdwn text in the Message field is enough and faster to set up.
- 1In the Channel field, type the target channel name (e.g. #project-wins)
- 2Click the expression toggle (the lightning bolt icon) next to the Message field
- 3Type {{ $json.slackMessage }} in the expression editor
- 4Leave 'As User' unchecked unless you want the message to appear from your personal account
- 5Click 'Execute Node' to send a test message to Slack
n8n Canvas > Webhook Node > Production URL > Active Toggle
Activate the workflow with the Production URL
Before activating, go back to the Webhook node and copy the Production URL (not the Test URL). Update your Todoist webhook registration — make a DELETE request to remove the old webhook, then POST a new one with the Production URL. Back in n8n, click the 'Active' toggle in the top right of the canvas to turn the workflow on. Todoist will now send completed task events to the production endpoint.
- 1Click the Webhook node and copy the 'Production URL'
- 2In Postman or curl, DELETE the existing Todoist webhook: DELETE https://api.todoist.com/sync/v9/webhooks/YOUR_WEBHOOK_ID
- 3Register a new Todoist webhook with the Production URL using the same POST request as Step 3
- 4In n8n, click the grey 'Inactive' toggle in the top-right corner to set the workflow to Active
- 5Complete a task in Todoist and confirm the Slack message fires within 5 seconds
Going live
Production Checklist
Before you turn this on for real, confirm each item.
Troubleshooting
Common errors and how to fix them.
Frequently Asked Questions
Common questions about this workflow.
Analysis
Use n8n for this if you want full control over the message format without paying per-task fees. Todoist users on active teams complete 50-200 tasks per week — at that volume, Zapier costs real money ($20-50/month on paid tiers) while n8n on a $5 VPS handles the same load for free. The other reason to pick n8n: the Todoist webhook sends project_id and user_id as raw integers, so you need a code node or HTTP lookup step to resolve them to readable names. n8n's Code node and chained HTTP Request nodes handle this cleanly in a single workflow. If your team has zero technical people and no one will maintain a self-hosted instance, use Zapier instead — the setup takes 10 minutes and Zapier's Todoist integration resolves project names automatically.
The math here is straightforward. Each task completion runs 4 n8n nodes: Webhook, Code, HTTP Request (project lookup), Slack. That's one execution per completed task. A 10-person team completing 20 tasks/day = 600 executions/month. n8n Cloud's free tier gives you 2,500 executions/month — this workflow fits comfortably within it at no cost. Zapier's free tier caps at 100 tasks/month, so you'd hit the wall in the first week. Make's free tier gives 1,000 operations/month — at 4 operations per run, that's 250 task completions before you pay. Self-hosted n8n has no execution limits at all, just server costs.
Zapier has one real advantage here: its Todoist trigger resolves project names automatically — no API lookup step needed. That saves two nodes and 10 minutes of setup. Make's advantage is its visual router module, which makes filtering by project or priority easier to read and maintain than an n8n IF/Switch chain. Power Automate can do this workflow but Todoist has no official Power Automate connector, so you'd build a custom HTTP trigger that takes 3x as long to configure. Pipedream is the closest competitor to n8n for this use case — its Todoist event source handles the webhook registration for you, skipping the Postman step entirely. For most developers, that's a meaningful time saver. n8n still wins on self-hosting cost and the ability to keep all data on your own infrastructure, which matters for teams with privacy constraints.
Three things you'll hit after setup. First: Todoist's webhook verification ping. When you first register the webhook, Todoist sends a POST with no event_data to confirm the endpoint is alive. If your Code node doesn't handle this, it throws an error on the very first execution — add a guard clause returning [] when event_data is absent. Second: the Slack channel membership issue. n8n's Slack app needs to be explicitly added to private channels — it won't auto-join and will return a cryptic not_in_channel error instead. Third: Todoist's webhook auto-disable behavior. Ten consecutive non-200 responses from your n8n endpoint and Todoist silently stops sending events. If your n8n instance restarts or errors during a deploy, you can lose the webhook without any notification. Build a weekly sanity check — a scheduled n8n workflow that hits the Todoist webhooks list API and alerts you if the webhook is missing or inactive.
Ideas for what to build next
- →Route completions to different Slack channels by project — Add a Switch node between the merge Code node and the Slack node. Map specific Todoist project_ids to their corresponding Slack channels — completions from 'Website Redesign' go to #design-wins, completions from 'Q4 Sales' go to #sales-wins.
- →Send a daily digest instead of per-task messages — Replace the webhook trigger with a Schedule trigger set to 9 AM daily. Query the Todoist Sync API for all tasks completed in the past 24 hours, group them by project, and post a single formatted summary to Slack instead of one message per task.
- →Add a Todoist comment when the Slack post succeeds — After the Slack node, add an HTTP Request node that POSTs a comment to the completed task via https://api.todoist.com/rest/v2/comments. The comment can say 'Announced in #project-wins at [time]' — creating a paper trail directly on the task.
Related guides
How to Send Weekly Todoist Reports to Slack with Pipedream
~15 min setup
How to Send Weekly Todoist Reports to Slack with Power Automate
~15 min setup
How to Send Weekly Todoist Reports to Slack with n8n
~20 min setup
How to Send Weekly Todoist Reports to Slack with Zapier
~8 min setup
How to Send Weekly Todoist Reports to Slack with Make
~12 min setup
How to Assign Todoist Tasks from Slack Mentions with Pipedream
~15 min setup