

How to Send Weekly Todoist Reports to Slack with n8n
Every Friday, n8n pulls the past 7 days of completed Todoist tasks, counts completions by project, and posts a formatted summary to a Slack channel for leadership review.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Engineering or product teams who already use Todoist for task tracking and want a zero-effort Friday summary in Slack without building a dashboard.
Not ideal for
Teams that need real-time task updates throughout the day — use a webhook-based notification workflow instead.
Sync type
scheduledUse case type
reportingReal-World Example
A 12-person product team at a SaaS company uses this to post a Friday 4pm Slack digest to #leadership showing how many tasks each project completed that week. Before automation, the project manager spent 20–30 minutes every Friday manually counting completions in Todoist and copy-pasting into Slack. Now the report shows up automatically with per-project breakdowns and a total completion count.
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 Content | content | |
| Project ID | project_id | |
| Completed At | completed_at | |
| Project Name | name | |
| Completion Count | ||
| Week Start Date | ||
| Slack Channel | ||
1 optional field▸ show
| Total Completions |
Step-by-Step Setup
n8n Dashboard > + New Workflow
Create a new n8n workflow
Open your n8n instance and click the '+ New Workflow' button in the top-right corner of the dashboard. Give it a clear name like 'Weekly Todoist → Slack Report'. You'll land on an empty canvas with a single gray 'Add first step' node in the center. Everything you build will chain off this canvas left-to-right.
- 1Click '+ New Workflow' in the top-right of the n8n dashboard
- 2Click the pencil icon next to 'My workflow' at the top and rename it 'Weekly Todoist → Slack Report'
- 3Click 'Save' in the top-right to register the name
Canvas > Add first step > Schedule Trigger
Add a Schedule trigger
Click the gray 'Add first step' node on the canvas. In the node picker that slides in from the right, search for 'Schedule' and select the 'Schedule Trigger' node. Set the trigger to run every Friday at 4:00 PM in your team's local timezone — this is critical to get right before anything else. The Schedule Trigger uses cron syntax under the hood; n8n exposes a dropdown UI for common intervals so you don't need to write raw cron.
- 1Click the gray 'Add first step' node
- 2Type 'Schedule' in the search box and select 'Schedule Trigger'
- 3Set 'Trigger Interval' to 'Weeks'
- 4Set 'Day of Week' to 'Friday'
- 5Set 'Hour' to '16' and 'Minute' to '0'
- 6Set 'Timezone' to your team's local timezone from the dropdown
Todoist Web App > Settings > Integrations > Developer > API token
Connect Todoist credentials
Add a new node after the Schedule Trigger by clicking the '+' connector on its right edge. Search for 'Todoist' and select the 'Todoist' node. In the node settings, click 'Credential for Todoist API' and then '+ Create New Credential'. n8n will prompt you to paste a Todoist API token. You get this from Todoist's web app under Settings > Integrations > Developer.
- 1Click the '+' connector on the right edge of the Schedule Trigger node
- 2Search 'Todoist' and click the Todoist node
- 3Click 'Credential for Todoist API' dropdown then '+ Create New Credential'
- 4Open Todoist in another tab: Settings > Integrations > Developer, copy your API token
- 5Paste the token into n8n's credential field and click 'Save'
Todoist Node > Resource: Task > Operation: Get All
Fetch completed tasks from the past 7 days
With the Todoist node open, set 'Resource' to 'Task' and 'Operation' to 'Get All'. You need to filter by completion status and date range. Todoist's REST API v2 doesn't support completed task queries directly — you must use the Sync API endpoint via an HTTP Request node instead (see Step 5). For now, set this node's Operation to 'Get All' with 'Filter' set to 'today' just to confirm auth works, then you'll replace it.
- 1Set 'Resource' to 'Task'
- 2Set 'Operation' to 'Get All'
- 3Click 'Test step' to confirm tasks load
- 4Verify your projects appear in the output panel on the right
Canvas > HTTP Request Node > Parameters
Fetch completed tasks via Todoist Sync API
Delete the Todoist node from Step 4 and replace it with an 'HTTP Request' node connected directly to the Schedule Trigger. The Todoist Sync API endpoint for completed tasks is https://api.todoist.com/sync/v9/items/completed/get_all. You'll pass your API token as a Bearer token in the Authorization header and set since as a query parameter calculated 7 days back from today. Use n8n's expression editor to compute the date dynamically.
- 1Add an HTTP Request node after the Schedule Trigger
- 2Set 'Method' to 'GET'
- 3Set 'URL' to 'https://api.todoist.com/sync/v9/items/completed/get_all'
- 4Under 'Authentication', select 'Generic Credential Type', choose 'Header Auth', set Header Name to 'Authorization' and Header Value to 'Bearer YOUR_TODOIST_TOKEN'
- 5Add Query Parameter: Name = 'since', Value = '{{ $now.minus({days: 7}).toISO() }}'
- 6Add Query Parameter: Name = 'limit', Value = '200'
- 7Click 'Test step'
Canvas > Code Node > JavaScript
Extract and aggregate completions by project
Add a 'Code' node after the HTTP Request node. This is where you process the raw API response into a structured summary. The Sync API returns a nested JSON object, so you need to access items.items (double-nested). Write JavaScript to count completions per project_id, then map project IDs to human-readable names. See the Pro Tip code section for the full transformation script.
- 1Click '+' after the HTTP Request node and search for 'Code'
- 2Select 'Code' node and set 'Language' to 'JavaScript'
- 3Set 'Mode' to 'Run Once for All Items'
- 4Paste the aggregation script from the Pro Tip section into the code editor
- 5Click 'Test step' and verify the output shows one item per project with a count field
Canvas > HTTP Request Node (second) > REST v2 Projects endpoint
Fetch project names from Todoist
The Sync API returns project_id values, not names. Add a second HTTP Request node before the Code node (between Steps 5 and 6) to fetch all projects. Use GET https://api.todoist.com/rest/v2/projects with the same Bearer token. This returns an array of project objects with id and name fields. Pass this data into the Code node alongside the completed tasks so you can do the ID-to-name lookup inside one Code node.
- 1Add a second HTTP Request node between the completed-tasks node and the Code node
- 2Set Method to 'GET', URL to 'https://api.todoist.com/rest/v2/projects'
- 3Add the same Bearer token Authorization header
- 4In the Code node, reference this node's output using $('HTTP Request Projects').all()
api.slack.com/apps > Your App > OAuth & Permissions > Bot Token Scopes
Connect Slack credentials
Add a Slack node after the Code node. Click 'Credential for Slack API' and select '+ Create New Credential'. Choose 'OAuth2' as the auth type — n8n will walk you through authorizing a Slack app. If you don't have a Slack app yet, you'll need to create one at api.slack.com/apps, add the chat:write and channels:read scopes, install it to your workspace, and paste the Bot OAuth Token into n8n.
- 1Add a Slack node after the Code node
- 2Click 'Credential for Slack API' > '+ Create New Credential'
- 3Go to api.slack.com/apps and create or open your existing Slack app
- 4Under 'OAuth & Permissions', add scopes: chat:write, channels:read
- 5Click 'Install to Workspace' and copy the 'Bot User OAuth Token'
- 6Paste the token into n8n's Slack credential field and click 'Save'
Slack Node > Resource: Message > Operation: Post > Channel + Text
Format and send the Slack message
In the Slack node, set 'Resource' to 'Message' and 'Operation' to 'Post'. Set 'Channel' to the channel ID or name where leadership reviews updates (e.g., #leadership-updates). For the message body, use n8n's expression editor to build a formatted string from the Code node's output. Use Slack's Block Kit or a plain mrkdwn text block with *bold* project names and task counts on separate lines.
- 1Set 'Resource' to 'Message' and 'Operation' to 'Post'
- 2Set 'Channel' to your target channel name or ID
- 3Set 'Text' to a dynamic expression referencing the Code node output (see Pro Tip for the full formatter)
- 4Enable 'Blocks' if you want structured Block Kit layout instead of plain text
- 5Click 'Test step' to send a test message to the channel
channel: {{channel}}
ts: {{ts}}
Node Settings > Continue on Fail | Canvas > Error Branch > Slack Alert Node
Add error handling with a fallback notification
Click the Slack node, then open the 'Settings' tab inside the node panel. Enable 'Continue on Fail' to prevent the workflow from silently dying if Slack rejects the message. Add a separate Slack node connected to the error output of the Code node and the HTTP Request nodes — this fallback node sends a plain alert to a #alerts channel if the data fetch fails. This takes 5 extra minutes and saves you from missing a report without knowing why.
- 1Click the Code node, open the 'Settings' tab, enable 'Continue on Fail'
- 2Do the same for both HTTP Request nodes
- 3Hover over the Code node and click the red error output connector
- 4Add a Slack node on the error branch
- 5Set its channel to '#alerts' and text to 'Weekly Todoist report failed — check n8n workflow logs'
Canvas > Top-right toggle > Active | Executions tab
Activate the workflow
Click the gray 'Inactive' toggle in the top-right of the canvas and flip it to 'Active'. n8n will now run this workflow automatically every Friday at 4:00 PM in your configured timezone. The first real execution happens at the next scheduled Friday — click 'Execute Workflow' manually now to confirm everything works end-to-end before then. Check the Executions tab to review the full run log.
- 1Click 'Save' to save the current workflow state
- 2Click 'Execute Workflow' to run it manually right now
- 3Verify the Slack message appears in your target channel
- 4Click the 'Inactive' toggle to switch it to 'Active'
- 5Open the Executions tab and confirm the manual run shows a green success status
Paste this into the Code node (set to 'Run Once for All Items'). It pulls completed tasks from the Sync API node, fetches project names from the separate REST v2 node, groups completions by project, builds the formatted Slack message string, and returns a single item containing the final text ready for the Slack node.
JavaScript — Code Node// Node names assumed:▸ Show code
// Node names assumed: // 'HTTP Completed Tasks' = Sync API response // 'HTTP Projects' = REST v2 projects list
... expand to see full code
// Node names assumed:
// 'HTTP Completed Tasks' = Sync API response
// 'HTTP Projects' = REST v2 projects list
const completedRaw = $('HTTP Completed Tasks').all();
const projectsRaw = $('HTTP Projects').all();
// Extract the items array from the Sync API response
const tasks = completedRaw[0].json.items || [];
// Build a project ID → name lookup map
const projectMap = {};
for (const p of projectsRaw[0].json) {
projectMap[p.id] = p.name;
}
// Group tasks by project_id
const grouped = {};
for (const task of tasks) {
const pid = task.project_id;
if (!grouped[pid]) {
grouped[pid] = { name: projectMap[pid] || `Project ${pid}`, tasks: [] };
}
grouped[pid].tasks.push(task.content);
}
// Calculate week range label
const now = new Date();
const weekStart = new Date(now);
weekStart.setDate(now.getDate() - 7);
const fmt = (d) => d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
const weekLabel = `${fmt(weekStart)} – ${fmt(now)}`;
// Build Slack message text
let totalCount = 0;
let lines = [`*Weekly Progress Report — ${weekLabel}*\n`];
for (const pid of Object.keys(grouped)) {
const proj = grouped[pid];
const count = proj.tasks.length;
totalCount += count;
lines.push(`*${proj.name}* — ${count} task${count !== 1 ? 's' : ''} completed`);
for (const t of proj.tasks) {
lines.push(` • ${t}`);
}
lines.push('');
}
lines.push(`*Total: ${totalCount} task${totalCount !== 1 ? 's' : ''} completed this week*`);
return [{ json: { slackMessage: lines.join('\n') } }];Scaling Beyond 200+ tasks completed per week+ Records
If your volume exceeds 200+ tasks completed per week records, apply these adjustments.
Paginate the Sync API with offset
The Sync API's max limit is 200 items per call. Add a loop using n8n's Loop Over Items node: fetch page 1, check if the response returned exactly 200 items, and if so fetch page 2 with offset=200. Continue until a response returns fewer than 200 items.
Merge paginated results in the Code node
Collect all paginated responses into a single array before aggregating. Pass each page's items array into a shared accumulator variable. Run the project grouping logic once after all pages are collected, not once per page — otherwise your counts will be fragmented across multiple Slack messages.
Watch the Todoist Sync API rate limit
Todoist enforces a limit of 450 requests per 15 minutes per user token. If your pagination loop makes many calls in quick succession for large teams, add a Wait node between paginated requests — set it to 2 seconds. This keeps you well inside the rate limit even at high volumes.
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 automation stack, want to keep Todoist API tokens off third-party servers, or need the Code node to do non-trivial data transformation — grouping tasks by project, building formatted strings, handling edge cases like empty weeks. n8n gives you a real JavaScript environment, not a formula box with limited functions. The one scenario where you'd skip n8n: if your team has no one comfortable reading a JavaScript error message and you just want a basic task-count-to-Slack message, Make's scenario builder with its Array/Collection modules will get you there faster without touching code.
Cost math: this workflow makes 3 API calls per run (Todoist Sync API, Todoist projects REST API, Slack post) and runs 52 times per year. That's 156 executions annually on n8n Cloud. n8n Cloud's Starter plan is $20/month and includes 2,500 executions/month — this workflow uses about 13 executions/month, which is well under the limit even with multiple other workflows running. Self-hosted n8n is free with your own server costs. Compare that to Zapier, where the same workflow requires a multi-step Zap — the Schedule trigger plus HTTP Request steps — which runs on the Professional plan at $49/month minimum. You're paying 2.5x more on Zapier for a workflow that's actually harder to build there.
Make handles this well with its HTTP modules and the built-in Array Aggregator — no custom code needed if your formatting requirements are simple. Zapier can technically do it with Code by Zapier but the lack of a real code editor makes debugging the Sync API response painful. Power Automate has a solid Schedule trigger and HTTP action but formatting multi-line Slack messages in its expression language (concat, replace, newline characters) takes longer to get right than n8n's JavaScript template literals. Pipedream is the strongest alternative: native Node.js steps, clean async/await syntax, and a built-in Todoist source. If you're already on Pipedream for other workflows, build it there — it'll feel more natural. n8n wins here if self-hosting matters to you or if you're already running other n8n workflows and don't want to add a second platform.
Three things you'll hit after setup: First, the Todoist Sync API returns project_id as a string in some responses and an integer in others depending on task age — your projectMap lookup will silently fail if you don't coerce both sides to strings with String(pid). Second, Slack's mrkdwn asterisks for bold (*text*) don't render in the Block Kit 'plain_text' element type — use 'mrkdwn' element type or switch to the plain text field in the Slack node. Third, n8n's Schedule Trigger doesn't retry if your server is down at exactly 4pm Friday. If uptime matters, add a second Schedule Trigger set to 4:15pm pointing to the same workflow — it will re-post, so add a simple deduplication flag using n8n's static data store to prevent double-posting.
Ideas for what to build next
- →Add per-assignee breakdowns — The Todoist Sync API returns a user_id on each completed task. Fetch collaborator data from the REST v2 /collaborators endpoint and extend the Code node to group by person — useful when leadership wants to see individual output, not just project totals.
- →Post a Monday goals digest — Add a second scheduled workflow that runs Monday morning and pulls all tasks due that week from Todoist's active task endpoint. Post it to the same Slack channel as a counterpart to Friday's completion report — so leadership sees what's planned and what got done.
- →Archive reports to Google Sheets — After the Slack node, add a Google Sheets node that appends one row per project per week with the project name, completion count, and week date. Over 8–12 weeks you'll have a trend dataset that's easy to pull into a chart without any manual tracking.
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 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
How to Assign Todoist Tasks from Slack Mentions with Power Automate
~15 min setup