Intermediate~15 min setupCommunication & Project ManagementVerified April 2026
Slack logo
Todoist logo

How to Post Todoist Standups to Slack with Pipedream

A scheduled Pipedream workflow pulls each team member's active Todoist tasks every morning and posts a formatted standup summary to a designated Slack channel.

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 of 5–20 people who already track work in Todoist and run async standups in Slack

Not ideal for

Teams using project tools like Jira or Linear — use n8n or Make instead, both have native integrations with richer query options

Sync type

scheduled

Use case type

reporting

Real-World Example

💡

A 12-person product team at a remote SaaS company runs async standups in #standup-product. Before automation, each person pasted their task list manually into Slack every morning — about 3 minutes per person, often skipped. Now Pipedream fires at 9:00 AM, pulls every member's due-today and overdue Todoist tasks via the REST API, and posts a single formatted digest. The channel sees consistent standup data every day with zero manual effort.

What Will This Cost?

Drag the slider to your expected monthly volume.

/mo
505005K50K

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

Skip the setup

Import this workflow directly into Pipedream

Copy the pre-built Pipedream blueprint and paste it straight into Pipedream. 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.

Todoist account with tasks assigned and due dates set — the workflow pulls nothing useful without them
Todoist OAuth access with 'task:read' scope — granted automatically via Pipedream's OAuth flow
Slack workspace admin or app installation rights — needed to authorize the Pipedream Slack app
Slack 'chat:write' and 'chat:write.public' scopes — required to post to public channels; 'chat:write' alone won't post to public channels
Pipedream account on any paid tier if you need runs more frequent than once per day, or free tier works for a single daily schedule

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Task Contentcontent
Due Datedue.date
Prioritypriority
Is Completedis_completed
4 optional fields▸ show
Project IDproject_id
Assignee IDassignee_id
Task URLurl
Labelslabels

Step-by-Step Setup

1

pipedream.com > Workflows > New Workflow

Create a new Pipedream workflow

Go to pipedream.com and sign in. Click 'New Workflow' in the top-right corner of the dashboard. Give it a clear name like 'Daily Standup — Todoist to Slack'. You'll land on the workflow canvas with an empty trigger slot at the top.

  1. 1Click the blue 'New Workflow' button in the top-right
  2. 2Type 'Daily Standup — Todoist to Slack' in the workflow name field
  3. 3Press Enter or click the checkmark to save the name
  4. 4Click the '+ Add Trigger' block at the top of the canvas
What you should see: You should see the trigger selection panel slide open on the right side of the screen.
Common mistake — Pipedream auto-saves workflow names only after you press Enter or click away. If you close the tab immediately, the name reverts to 'Untitled'. Set it before moving on.
2

Trigger Panel > Search > Schedule > Every Day

Set a daily schedule trigger

In the trigger panel, search for 'Schedule' and select the 'Schedule' source. Choose 'Every day' from the frequency dropdown. Set the time to 9:00 AM and select your team's timezone — this is critical for international teams. Pipedream runs the schedule in UTC by default until you change it.

  1. 1Type 'Schedule' in the trigger search box
  2. 2Click 'Schedule' under the 'Core' category
  3. 3Select 'Every Day' from the frequency dropdown
  4. 4Set the time field to '09:00'
  5. 5Open the timezone dropdown and select your team's local timezone (e.g., 'America/New_York')
What you should see: The trigger block shows 'Runs daily at 09:00 America/New_York' and a green 'Active' badge appears after you click Save.
Common mistake — Pipedream's free tier caps workflows at once per day for scheduled sources on some plans. Check your plan's scheduler limits before setting up multiple standup channels — each channel will need its own workflow if you split by team.
Pipedream
+
click +
search apps
Slack
SL
Slack
Set a daily schedule trigger
Slack
SL
module added
3

Workflow Canvas > + Add Step > Todoist > Get Active Tasks

Connect your Todoist account

Click '+ Add Step' below the trigger and search for 'Todoist'. Select the 'Get Active Tasks' action (action key: todoist-get-active-tasks). In the step configuration panel, click 'Connect Account' and authenticate with your Todoist credentials. You'll need a Todoist account that has access to the projects you want to pull from.

  1. 1Click '+ Add Step' directly below the trigger block
  2. 2Type 'Todoist' in the app search field
  3. 3Select 'Todoist' from the results
  4. 4Choose the 'Get Active Tasks' action
  5. 5Click 'Connect Account' and complete the OAuth login
What you should see: The Todoist step shows your account name in the 'Connected Account' dropdown and the action configuration fields appear below it.
Pipedream settings
Connection
Choose a connection…Add
click Add
Slack
Log in to authorize
Authorize Pipedream
popup window
Connected
green checkmark
4

Todoist Step > Configuration > Filter Field

Filter tasks by project or assignee

In the Todoist 'Get Active Tasks' step, find the 'Filter' field. Todoist's REST API accepts filter strings like 'today | overdue' to limit which tasks come back. Type your filter string here. If your team members each own a Todoist project, you can also set 'Project ID' to pull from a specific project. Run a test now — click 'Test' at the bottom of the step — to confirm tasks return.

  1. 1Click inside the 'Filter' input field in the Todoist step
  2. 2Type 'today | overdue' to capture due-today and overdue tasks
  3. 3Optionally set 'Project ID' if you want to scope tasks to one project
  4. 4Click the 'Test' button at the bottom of the step
  5. 5Expand the returned array to confirm your tasks appear in the output
What you should see: The test output panel shows a JSON array of task objects. Each object includes 'content', 'due', 'priority', and 'assignee_id' fields.
Common mistake — Todoist's filter syntax is case-sensitive and uses Todoist's own query language — not plain English. 'Today | Overdue' with capitals will fail silently and return zero tasks. Always lowercase.
Slack
SL
trigger
filter
Condition
matches criteria?
yes — passes through
no — skipped
Todoist
TO
notified
5

Workflow Canvas > + Add Step > Run Node.js Code

Add a Node.js code step to format the standup message

Click '+ Add Step' and choose 'Run Node.js code'. This is where you transform the raw Todoist task array into a readable Slack message. You'll map task content, priority, and due date into a formatted string. Paste the code from the Pro Tip section below directly into this step's code editor. The code groups tasks by priority and assembles a Block Kit-friendly Slack message payload.

  1. 1Click '+ Add Step' below the Todoist step
  2. 2Select 'Run Node.js code' from the step type list
  3. 3Clear the default boilerplate from the editor
  4. 4Paste your formatting code into the editor
  5. 5Click 'Test' to confirm the output includes a formatted 'blocks' array
What you should see: The test output shows a 'blocks' array with Slack Block Kit section blocks containing your task content, priority labels, and due dates.
Common mistake — The Todoist API returns priority as a number: 1=normal, 2=medium, 3=high, 4=urgent. This is inverted from what most people expect. Priority 4 is the red urgent flag in the Todoist UI. Your formatting code must map these correctly or standups will show wrong priority labels.

Paste this into your Node.js code step (Step 5 on the canvas). It reads the Todoist task array from the previous step's output, maps priority numbers to labels, flags overdue tasks, groups everything by priority, and returns a Slack Block Kit blocks array ready to drop into the Slack Send Message step.

JavaScript — Code Stepexport default defineComponent({
▸ Show code
export default defineComponent({
  async run({ steps, $ }) {
    const tasks = steps.todoist_get_active_tasks.$return_value;

... expand to see full code

export default defineComponent({
  async run({ steps, $ }) {
    const tasks = steps.todoist_get_active_tasks.$return_value;

    if (!tasks || tasks.length === 0) {
      return {
        blocks: [
          {
            type: 'section',
            text: {
              type: 'mrkdwn',
              text: ':white_check_mark: No tasks due today — enjoy the quiet.'
            }
          }
        ]
      };
    }

    const priorityMap = {
      4: { label: 'Urgent', emoji: ':red_circle:' },
      3: { label: 'High',   emoji: ':large_orange_circle:' },
      2: { label: 'Medium', emoji: ':large_yellow_circle:' },
      1: { label: 'Normal', emoji: ':white_circle:' }
    };

    const today = new Date().toISOString().split('T')[0];

    const sorted = [...tasks].sort((a, b) => b.priority - a.priority);

    const blocks = [
      {
        type: 'header',
        text: {
          type: 'plain_text',
          text: `:clipboard: Daily Standup — ${new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric' })}`,
          emoji: true
        }
      },
      { type: 'divider' }
    ];

    for (const task of sorted) {
      const { label, emoji } = priorityMap[task.priority] || priorityMap[1];
      const dueDate = task.due?.date || 'No due date';
      const isOverdue = task.due?.date && task.due.date < today;
      const overdueFlag = isOverdue ? ' :warning: *Overdue*' : '';

      const formattedDate = dueDate !== 'No due date'
        ? new Date(dueDate + 'T00:00:00').toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
        : 'No due date';

      blocks.push({
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: `${emoji} *${label}* — <${task.url}|${task.content}> · Due: ${formattedDate}${overdueFlag}`
        }
      });
    }

    blocks.push({ type: 'divider' });
    blocks.push({
      type: 'context',
      elements: [
        {
          type: 'mrkdwn',
          text: `${sorted.length} task${sorted.length !== 1 ? 's' : ''} · Pulled from Todoist at ${new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })}`
        }
      ]
    });

    return { blocks };
  }
});
message template
🔔 New Record: {{text}} {{user}}
channel: {{channel}}
ts: {{ts}}
#sales
🔔 New Record: Jane Smith
Company: Acme Corp
6

Workflow Canvas > + Add Step > Slack > Send Message

Connect your Slack account

Click '+ Add Step' and search for 'Slack'. Select the 'Send Message' action. Click 'Connect Account' and authorize Pipedream via OAuth. Pipedream will request the 'chat:write' and 'chat:write.public' scopes — both are required. If you're posting to a private channel, you'll also need to invite the Pipedream Slack app to that channel manually inside Slack.

  1. 1Click '+ Add Step' below the Node.js code step
  2. 2Type 'Slack' in the app search
  3. 3Select 'Slack' and then 'Send Message'
  4. 4Click 'Connect Account' and complete the Slack OAuth flow
  5. 5Confirm the connected account name matches your workspace
What you should see: The Slack step shows your workspace name under 'Connected Account' and the configuration fields (Channel, Text, Blocks) become editable.
Common mistake — If your Slack workspace uses Enterprise Grid, standard OAuth may land on the wrong org. Confirm the workspace name shown in Pipedream matches the one where your standup channel lives before proceeding.
7

Slack Step > Channel > Blocks Field > Expression Picker

Configure the Slack message destination and payload

In the Slack 'Send Message' step, set the Channel field to your standup channel name, e.g. '#standup-product'. In the Blocks field, reference the output from your Node.js code step by clicking the '{{' expression picker and selecting 'steps.nodejs.$return_value.blocks'. Leave the Text field as a fallback string like 'Daily standup summary' — Slack uses this as a notification preview.

  1. 1Click the Channel field and type '#standup-product' or your channel name
  2. 2Click into the Blocks field
  3. 3Click the '{{' button to open the expression picker
  4. 4Navigate to your Node.js step and select '$return_value.blocks'
  5. 5Set the Text field fallback to 'Daily standup summary — see thread'
What you should see: The Blocks field shows a reference expression like '{{steps.format_standup.$return_value.blocks}}' and the Text field shows your fallback string.
Common mistake — Map fields using the variable picker — don't type field names manually. Hand-typed variable names often have invisible spacing errors that produce blank output.
8

Workflow Canvas > Run Now Button (top toolbar)

Test the full workflow end to end

Click 'Run Now' at the top of the workflow canvas to trigger a manual test run. Watch each step execute in sequence — green checkmarks indicate success. Open your Slack standup channel and confirm the message posted correctly. Check that task priorities, due dates, and task content all look right. If any step shows a red X, click it to read the error log.

  1. 1Click the grey 'Run Now' button in the top toolbar
  2. 2Watch each step tile turn green as they complete
  3. 3Open Slack and navigate to your standup channel
  4. 4Confirm the posted message shows the correct tasks and formatting
  5. 5If a step fails, click the red X icon on that step to read the error detail
What you should see: A formatted standup summary appears in your Slack channel within 10–15 seconds of clicking Run Now, showing today's and overdue tasks grouped by priority.
Common mistake — If the Todoist step returns an empty array during testing, it may be because your filter 'today | overdue' matches no tasks at the exact moment you test. Add a task due today in Todoist before running the test.
Pipedream
▶ Deploy & test
executed
Slack
Todoist
Todoist
🔔 notification
received
9

Node.js Code Step > Editor

Handle the case where no tasks are due

When Todoist returns zero tasks, your Node.js code will produce an empty blocks array and Slack will reject the message with a 'no_text' error. Add a short conditional in your code step that checks the array length. If it's zero, export a simple fallback message like 'No tasks due today — enjoy the quiet.' This prevents workflow errors on low-activity days.

  1. 1Open your Node.js code step
  2. 2Add an array length check before the blocks-building logic
  3. 3Return a minimal Slack block with the fallback text if the array is empty
  4. 4Click 'Test' to confirm the fallback triggers when task count is zero
What you should see: When no tasks match the filter, the workflow still completes successfully and posts 'No tasks due today — enjoy the quiet.' to Slack instead of failing.
10

Workflow Canvas > Deploy Button (top-right)

Deploy and activate the workflow

Click the grey 'Deploy' button in the top-right corner of the canvas. Pipedream will switch the workflow from draft mode to active. The toggle next to the workflow name will turn green. Your standup will now fire automatically every day at the time and timezone you set in Step 2. You can pause it anytime by flipping the toggle back.

  1. 1Click the 'Deploy' button in the top-right corner
  2. 2Confirm the prompt if one appears
  3. 3Check that the toggle next to the workflow name turns green
  4. 4Navigate to 'Workflow > Logs' to confirm the next scheduled run time
What you should see: The workflow status shows 'Active' and the Logs tab shows the next scheduled run timestamp matching your configured time.

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

VerdictWhy n8n for this workflow

Use Pipedream for this if your team has someone comfortable with JavaScript and wants full control over the standup message format. Pipedream's Node.js code step handles the Todoist priority inversion, overdue flagging, and Slack Block Kit formatting in one place without duct-taping multiple no-code actions together. The scheduled trigger fires reliably and the logs make debugging fast. If nobody on your team writes code, use Zapier instead — the formatter action handles basic task formatting without touching a single line of code.

Cost

Pipedream's pricing for this workflow is straightforward. Each daily run costs roughly 3 credits: 1 for the Todoist step, 1 for the code step, 1 for the Slack step. At Pipedream's free tier of 100 credits/month, you'll burn through in about 33 days — just over one month. The Basic plan at $19/month gives you 10,000 credits, which covers this workflow for 3,333 days at one run per day. In practice, even teams running 5 separate standup channels (5 workflows × 3 credits × 30 days = 450 credits/month) stay well within the Basic plan. Make's free tier covers the same workflow at zero cost indefinitely for a single channel.

Tradeoffs

Make handles this use case with a visual router that branches to multiple Slack channels in one scenario — no code needed. Zapier has a native Todoist 'New Task' trigger but no 'get all tasks on schedule' action, so you'd need workarounds. n8n has a Todoist node with better filter support and a Slack node that handles Block Kit natively, making it cleaner for teams self-hosting. Power Automate has no official Todoist connector, so you'd be hitting the REST API manually via HTTP actions — workable but slow to set up. Pipedream wins here because the code step eliminates the gap between what Todoist's API returns and what Slack's Block Kit expects, and the Node.js environment means you're not fighting a visual mapper to do basic data transformation.

Three things you'll hit after the first week. First, Todoist's 'today | overdue' filter includes tasks with no time component, which means a task due 'today' at 11:59 PM shows up in the 9 AM standup alongside actually overdue items — decide upfront if that's what you want. Second, if a team member revokes Todoist OAuth or changes their password, the workflow fails silently unless you add error alerting — Pipedream lets you add an error handler step that pings a Slack DM when a workflow fails, which takes 2 minutes to set up and is worth doing on day one. Third, Slack's Block Kit has a hard limit of 50 blocks per message. If a team has more than 45–48 tasks due in a single day, the message will be truncated without an error. Add a block count check in your code step and split into a thread reply if the count exceeds 40.

Ideas for what to build next

  • Add per-user task breakdownsExtend the code step to group tasks by assignee_id, then resolve each ID to a display name using the Todoist Users API. This turns one team digest into a per-person breakdown inside a single Slack message thread.
  • Post a weekly summary on FridaysDuplicate the workflow and change the Schedule trigger to fire every Friday at 4:00 PM. Adjust the Todoist filter to 'overdue | due before: +7 days' to give the team a forward-looking view going into the weekend.
  • Add a Slack emoji reaction acknowledgmentAfter the standup posts, add a second Slack step that adds a ':white_check_mark:' reaction to the message automatically. Then track who adds a thumbs-up reaction using Pipedream's Slack event source to measure standup engagement over time.

Related guides

Was this guide helpful?
Slack + Todoist overviewPipedream profile →