

How to Send Todoist Deadline Alerts to Slack with n8n
A scheduled n8n workflow checks Todoist every 15 minutes for tasks due today or overdue and posts formatted alerts to designated Slack channels.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Small to mid-sized project teams who track deadlines in Todoist and need automatic Slack nudges before tasks slip through the cracks.
Not ideal for
Teams managing hundreds of tasks per day — at that volume, digest-style daily summaries per channel work better than per-task pings.
Sync type
scheduledUse case type
notificationReal-World Example
A 12-person product team at a SaaS company uses this to post overdue sprint tasks into #product-ops every 15 minutes. Before the automation, the PM manually scanned Todoist each morning and missed same-day deadline slippage until standup. Now a Slack message fires within 15 minutes of a task going overdue, tagging the assignee by name.
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 ID | id | |
| Task Name | content | |
| Due Date | due.date | |
5 optional fields▸ show
| Project ID | project_id |
| Assignee ID | assignee_id |
| Priority | priority |
| Task URL | url |
| Description | description |
Step-by-Step Setup
n8n Canvas > + New Workflow
Create a new n8n workflow
Open your n8n instance and click the orange 'New Workflow' button in the top right of the canvas. Give the workflow a name like 'Todoist Deadline → Slack'. You'll land on an empty canvas with a single gray trigger node placeholder. This is where you'll build the entire flow from left to right.
- 1Click '+ New Workflow' in the left sidebar or top navigation
- 2Click the pencil icon next to 'My Workflow' and rename it to 'Todoist Deadline → Slack'
- 3Click the gray trigger node placeholder in the center of the canvas
Canvas > Trigger Node > Schedule Trigger
Add a Schedule trigger
Search for 'Schedule' in the node picker and select the Schedule Trigger node. Set the interval to every 15 minutes. This is the heartbeat of your workflow — it wakes the workflow up at regular intervals to check Todoist for approaching or overdue deadlines. Avoid setting this below 5 minutes; Todoist's REST API enforces rate limits and unnecessary polling adds no value.
- 1Type 'Schedule' in the node search panel
- 2Click 'Schedule Trigger' from the results
- 3Set 'Trigger Interval' to 'Minutes'
- 4Set the interval value to '15'
- 5Click 'Back to Canvas'
Canvas > + Node > Todoist > Credentials > Create New
Connect your Todoist account
Click the '+' button to the right of the Schedule Trigger to add the next node. Search for 'Todoist' and select the Todoist node. In the parameters panel, click 'Create New Credential'. You'll be prompted to enter a Todoist API token — find this under Todoist Settings > Integrations > Developer > API token. Copy the token and paste it into n8n, then click 'Save'.
- 1Click the '+' connector on the right edge of the Schedule Trigger
- 2Search 'Todoist' in the node picker
- 3Select 'Todoist' from the results
- 4Click 'Credential for Todoist API' dropdown and select 'Create New'
- 5Paste your Todoist API token into the 'API Token' field
- 6Click 'Save' to store the credential
Todoist Node > Resource: Task > Operation: Get All > Filters
Configure Todoist to fetch tasks with due dates
With the Todoist node selected, set the Resource to 'Task' and the Operation to 'Get All'. Under Filters, add a filter for 'Filter' and enter the Todoist filter string: 'overdue | today'. This uses Todoist's native filter syntax to return all tasks that are due today or already past due. Leave the limit at 100 unless your team has unusually large projects.
- 1Set 'Resource' to 'Task'
- 2Set 'Operation' to 'Get All'
- 3Toggle on 'Additional Fields'
- 4In the 'Filter' field type: overdue | today
- 5Leave 'Limit' at 100
Canvas > + Node > Code
Add a Code node to calculate urgency and format messages
Add a Code node after the Todoist node. This is where you calculate whether each task is overdue or due today, assign urgency labels, and build the Slack message text. Paste the JavaScript below into the code editor. The code iterates over every returned task, computes the difference between today's date and the task's due date, and tags each task as OVERDUE or DUE TODAY before passing it downstream.
- 1Click the '+' connector on the Todoist node
- 2Search 'Code' in the node picker and select the Code node
- 3Set 'Language' to 'JavaScript'
- 4Set 'Mode' to 'Run Once for All Items'
- 5Paste the pro tip code into the code editor
- 6Click 'Test Step' to verify output
Paste this into the first Code node (Step 5). It runs once for all items, computes urgency and days overdue, resolves assignee IDs to Slack usernames via a hardcoded map (replace with your team's IDs), and builds the full Slack message string. The second block handles deduplication using n8n's static workflow data — paste that into the second Code node (Step 6).
JavaScript — Code Node// ── CODE NODE 1: Urgency calculation + message formatting ──▸ Show code
// ── CODE NODE 1: Urgency calculation + message formatting ── // Mode: Run Once for All Items const items = $input.all();
... expand to see full code
// ── CODE NODE 1: Urgency calculation + message formatting ──
// Mode: Run Once for All Items
const items = $input.all();
const today = new Date();
today.setHours(0, 0, 0, 0);
// Replace these with your actual Todoist assignee_id → Slack username mappings
const assigneeMap = {
'38291047': '@sarah.chen',
'38291055': '@marcus.okafor',
'38291062': '@james.liu',
};
const priorityLabels = {
4: 'Urgent',
3: 'High',
2: 'Normal',
1: 'Low',
};
const results = [];
for (const item of items) {
const task = item.json;
// Skip tasks with no due date
if (!task.due || !task.due.date) continue;
const dueDate = new Date(task.due.date);
dueDate.setHours(0, 0, 0, 0);
const diffMs = today - dueDate;
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
let urgencyLabel;
let emoji;
if (diffDays > 0) {
urgencyLabel = `OVERDUE (${diffDays} day${diffDays === 1 ? '' : 's'})`;
emoji = '⚠️';
} else if (diffDays === 0) {
urgencyLabel = 'DUE TODAY';
emoji = task.priority === 4 ? '🔴' : '📌';
} else {
// Not due yet — skip (remove this block if you want upcoming tasks too)
continue;
}
const assignee = assigneeMap[task.assignee_id] || 'Unassigned';
const priority = priorityLabels[task.priority] || 'Normal';
const formattedDue = dueDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
const slackMessage = [
`${emoji} *${urgencyLabel}* — ${task.content}`,
`📅 Due: ${formattedDue} | Priority: ${priority}`,
`👤 Assignee: ${assignee}`,
`🔗 ${task.url}`,
].join('\n');
results.push({
json: {
task_id: task.id,
task_name: task.content,
due_date: task.due.date,
days_overdue: diffDays,
urgency_label: urgencyLabel,
assignee_slack: assignee,
slack_message: slackMessage,
},
});
}
return results;
// ── CODE NODE 2: Deduplication using static workflow data ──
// Mode: Run Once for All Items
// Paste this into the SECOND Code node
/*
const items = $input.all();
const staticData = $getWorkflowStaticData('global');
// Initialize the notified IDs store if it doesn't exist
if (!staticData.notifiedIds) {
staticData.notifiedIds = [];
}
const newItems = [];
const newlyNotified = [];
for (const item of items) {
const taskId = item.json.task_id;
if (!staticData.notifiedIds.includes(taskId)) {
newItems.push(item);
newlyNotified.push(taskId);
}
}
// Add newly notified IDs to the store
staticData.notifiedIds = [...staticData.notifiedIds, ...newlyNotified];
// Cap the store at 500 IDs to prevent unbounded growth
if (staticData.notifiedIds.length > 500) {
staticData.notifiedIds = staticData.notifiedIds.slice(-500);
}
return newItems;
*/channel: {{channel}}
ts: {{ts}}
Canvas > + Node > Code (second instance)
Add a deduplication check with n8n's Static Data
To avoid spamming Slack with the same task every 15 minutes, add a second Code node that uses n8n's $getWorkflowStaticData() to store IDs of tasks already notified. On each run, the node filters out tasks whose IDs are already in the static data store and only passes new ones downstream. It then updates the store with the newly notified IDs. Tasks are cleared from the store once they no longer appear in the Todoist filter (meaning they were completed or rescheduled).
- 1Click the '+' connector on the first Code node
- 2Add another Code node
- 3Set Mode to 'Run Once for All Items'
- 4Paste the deduplication logic from the pro tip code's second function
- 5Click 'Test Step' and verify only new task IDs pass through
Canvas > + Node > Slack > Credentials > OAuth2
Connect your Slack account
Add a Slack node after the deduplication Code node. Click 'Create New Credential' and select 'OAuth2'. n8n will open a pop-up to authorize your Slack workspace. Sign in and grant the requested permissions — you need chat:write and channels:read at minimum. If you want to post to private channels, also grant chat:write.customize and the bot must be invited to those channels manually.
- 1Click '+' after the deduplication Code node
- 2Search 'Slack' and select the Slack node
- 3Click 'Credential for Slack API' and choose 'Create New'
- 4Select 'OAuth2 (recommended)'
- 5Click 'Connect my account' and authorize in the Slack pop-up
- 6Select your workspace and click 'Allow'
Slack Node > Resource: Message > Operation: Send
Configure the Slack message node
With the Slack node selected, set Resource to 'Message' and Operation to 'Send'. For 'Channel', type the exact channel name including the '#' symbol (e.g. #project-deadlines). In the 'Text' field, click the expression toggle (the '{ }' icon) and reference the slack_message field from the Code node output: {{ $json.slack_message }}. This injects the formatted message text built in Step 5.
- 1Set 'Resource' to 'Message'
- 2Set 'Operation' to 'Send'
- 3Enter your target channel name in 'Channel' (e.g. #project-deadlines)
- 4Click the expression toggle '{ }' next to the 'Text' field
- 5Type: {{ $json.slack_message }}
- 6Optionally set 'Username' to 'Deadline Bot' for a cleaner display name
Todoist Node > ... menu > Add Error Output > connect to Slack (alerts channel)
Add error handling with a Stop and Error node
Click the three-dot menu on the Todoist node and select 'Add Error Output'. Connect the error output to a Slack node configured to post to a #workflow-alerts or #ops channel with the message 'Todoist Deadline workflow failed: {{ $json.message }}'. Do the same for the Slack node itself. This means if the Todoist API is down or your Slack token expires, you get notified instead of silently missing deadline alerts.
- 1Right-click the Todoist node and select 'Add Error Output'
- 2Connect the red error output connector to a new Slack node
- 3Configure that Slack node to post to your internal alerts channel
- 4Set the message text to: 'Deadline workflow error: {{ $json.message }}'
- 5Repeat for the main Slack node's error output
Canvas > Test Workflow button (top right)
Test end-to-end with a real Todoist task
Create a test task in Todoist with today's date as the due date. Go back to n8n and click 'Test Workflow' (not 'Execute Workflow' — that saves first). Watch each node light up green as data flows through. Verify the Slack message appears in your channel with the correct task name, due date, and urgency label. Check that running the test a second time produces no duplicate Slack message, confirming deduplication works.
- 1Create a Todoist task titled 'TEST: Deadline check' due today
- 2Return to n8n and click the 'Test Workflow' button
- 3Watch each node turn green as execution proceeds
- 4Verify the message appears in Slack within 30 seconds
- 5Click 'Test Workflow' again and confirm no duplicate message is sent
Canvas > Active/Inactive toggle (top right)
Activate the workflow
Click the gray 'Inactive' toggle in the top right of the canvas to switch it to 'Active'. n8n will immediately schedule the first execution based on your 15-minute interval. The workflow will now run automatically without you needing to keep the browser open. Check the 'Executions' tab after 30 minutes to confirm the first scheduled run completed successfully.
- 1Click 'Save' to save the workflow
- 2Click the 'Inactive' toggle to flip it to 'Active'
- 3Confirm the toggle turns green and shows 'Active'
- 4Navigate to the 'Executions' tab in the left sidebar
- 5Wait 15 minutes and refresh — you should see a completed execution entry
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 self-host your stack, have tasks with complex routing logic (per-project channels, priority-based filtering, assignee tagging), or want zero per-execution cost. The code node gives you full control — you can compute days overdue, format messages exactly how your team wants, and handle Todoist's occasional null fields without workarounds. The one scenario where you'd skip n8n: if your team has no one comfortable reading 30 lines of JavaScript and you just want alerts firing in under 10 minutes. That's a Zapier job.
At a 15-minute polling interval, this workflow executes ~2,880 times per month. Each execution is a single workflow run regardless of how many tasks are returned. On n8n Cloud, the Starter plan caps at 2,500 executions/month ($20/month) and the Pro plan gives you 10,000 ($50/month). Self-hosted n8n is free — you pay only for server costs. Zapier charges per task, not per run: if 5 tasks fire in one check, that's 5 Zap tasks. At $19.99/month for 750 tasks, 5 overdue tasks per check × 96 checks/day × 30 days = 14,400 tasks/month, which requires Zapier's $49/month Professional plan. n8n Cloud Pro is $50/month and covers this volume with no task-count math.
Make handles this use case well with its built-in scheduler and Todoist + Slack modules — no code required, and the visual router handles per-project channel logic cleanly. Zapier is faster to set up (roughly 8 minutes) but hits task-count limits fast on active projects. Power Automate has a Todoist connector but it's limited to premium plans and the connector doesn't support Todoist's filter syntax, so you'd have to use HTTP requests anyway. Pipedream's Node.js environment is functionally equivalent to n8n's Code node but costs $0 for low-volume use — if you're self-hosting n8n purely for this one workflow, Pipedream is cheaper. n8n wins when this workflow is part of a larger self-hosted automation stack and you're already running the instance.
Three things you'll hit after setup. First: Todoist's filter API returns tasks based on the account's timezone setting, not UTC. If your n8n server is in UTC and your Todoist account timezone is set to US/Pacific, tasks due 'today' in Pacific time won't appear until 8 AM UTC — that's a 5-hour gap where overdue tasks don't fire. Fix it by setting both n8n's instance timezone and your Todoist account timezone to match. Second: the static data store that prevents duplicate notifications is tied to the workflow's activation state. If you deactivate and reactivate the workflow (e.g., during debugging), the store resets and every currently-overdue task fires again as if it's new. Expect a burst of duplicate Slack messages after any workflow reactivation. Third: Todoist's task URL field (url) is present in the v2 REST API but absent in older v1 endpoints. If you migrated an older Todoist integration, confirm you're hitting api.todoist.com/rest/v2/tasks — v1 URLs will return tasks without the url field and your Slack messages will have a broken link.
Ideas for what to build next
- →Add a daily digest instead of per-task pings — Change the Schedule Trigger to fire once per day at 8 AM and modify the Slack node to send a single aggregated message listing all overdue and due-today tasks in a numbered list. This reduces notification fatigue while keeping the team informed.
- →Route alerts to per-project Slack channels — Add a Switch node between the Code node and the Slack node that checks task.project_id and routes each task to a different Slack channel based on which project it belongs to. Map your Todoist project IDs to channel names in a lookup object inside the Switch node.
- →Sync task completion back to a Slack thread — Add a second workflow that uses a Todoist webhook (via n8n's webhook trigger) to listen for task completion events and post a ✅ reply in the original Slack notification thread, giving the team a closed-loop confirmation without checking Todoist manually.
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