

How to Create Notion Tasks from Slack with n8n
When a Slack message gets a specific emoji reaction, n8n captures it via webhook and creates a new task entry in a Notion database with the message text, sender, channel, and timestamp.
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 surface action items inside Slack and need them tracked in Notion without copy-pasting.
Not ideal for
Teams who want two-way sync — when a Notion task updates, this workflow does not reflect that back into Slack.
Sync type
real-timeUse case type
routingReal-World Example
A 12-person product team at a B2B SaaS company uses this to capture feature requests that surface in #customer-feedback by reacting with a 📋 emoji. Before this workflow, a PM manually checked the channel twice a day and copy-pasted requests into Notion — missing roughly 3-4 items per week. Now every reacted message becomes a Notion task within 10 seconds.
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 Title | ||
7 optional fields▸ show
| Status | |
| Source Channel | |
| Slack Message URL | |
| Requested By (User ID) | |
| Created Date | |
| Message Timestamp | |
| Emoji Used |
Step-by-Step Setup
api.slack.com/apps > Your App > Event Subscriptions
Create a Slack App and enable Event Subscriptions
Go to api.slack.com/apps and click 'Create New App'. Choose 'From scratch', name it something like 'Notion Task Bot', and select your workspace. You need a dedicated app here because n8n's webhook URL must be registered with Slack's Event Subscriptions system — you can't do this through a generic OAuth token. Once the app is created, navigate to 'Event Subscriptions' in the left sidebar and toggle 'Enable Events' to On.
- 1Go to api.slack.com/apps and click 'Create New App'
- 2Select 'From scratch'
- 3Enter an app name and select your target workspace
- 4Click 'Create App'
- 5In the left sidebar, click 'Event Subscriptions'
- 6Toggle 'Enable Events' to On — leave the Request URL blank for now
Paste this into the Code node in Step 7. It pulls the message text, formats the Slack timestamp into a human-readable date, builds the Slack deep-link URL from the channel and timestamp, truncates titles over 100 characters so Notion doesn't reject them, and outputs a clean object ready for the Notion node.
JavaScript — Code Node// Code node — runs after conversations.history HTTP Request▸ Show code
// Code node — runs after conversations.history HTTP Request // Input: HTTP response from Slack API // Output: structured task object for Notion
... expand to see full code
// Code node — runs after conversations.history HTTP Request
// Input: HTTP response from Slack API
// Output: structured task object for Notion
const items = $input.all();
const results = [];
for (const item of items) {
const response = item.json;
// Guard: API call failed
if (!response.ok || !response.messages || response.messages.length === 0) {
throw new Error(`Slack API error: ${response.error || 'No messages returned'}`);
}
const message = response.messages[0];
const rawText = message.text || '(no text content)';
// Truncate long messages — Notion title max is 2000 chars,
// but over 100 chars makes the task list unreadable
const taskTitle = rawText.length > 100
? rawText.substring(0, 97) + '...'
: rawText;
// Pull webhook event data from the trigger node
const webhookData = $('Webhook').item.json.event;
const channelId = webhookData.item.channel;
const slackTs = webhookData.item.ts;
const userId = webhookData.user;
const emojiName = webhookData.reaction;
// Convert Slack epoch timestamp to ISO date string
// Slack ts format: '1704326400.000200' — take the integer part
const epochSeconds = parseInt(slackTs.split('.')[0], 10);
const createdDate = new Date(epochSeconds * 1000).toISOString().split('T')[0];
// Build Slack deep link URL
// Format: /archives/CHANNEL_ID/pTIMESTAMP (no dot in timestamp)
const tsForUrl = slackTs.replace('.', '');
const workspaceDomain = 'yourworkspace'; // replace with your Slack subdomain
const messageUrl = `https://${workspaceDomain}.slack.com/archives/${channelId}/p${tsForUrl}`;
results.push({
json: {
taskTitle,
slackUser: userId,
channelId,
slackTimestamp: slackTs,
messageUrl,
createdDate,
emojiUsed: emojiName,
rawMessageText: rawText
}
});
}
return results;n8n > New Workflow > + Add Node > Webhook
Set up the Slack Webhook node in n8n
Open your n8n instance and create a new workflow. Add a 'Webhook' node as the first node — not the Slack trigger node, because Slack's Event API requires a URL challenge verification that the generic Webhook node handles better. Set the HTTP method to POST and copy the generated webhook URL. You'll paste this into Slack's Event Subscriptions page next.
- 1Click '+ Add first step' in the center of the canvas
- 2Search for 'Webhook' and select it
- 3Set HTTP Method to 'POST'
- 4Set Response Mode to 'Using Respond to Webhook Node' — you'll add that node later
- 5Click 'Listen for Test Event' to activate the URL
- 6Copy the Test URL shown at the top of the node panel
api.slack.com/apps > Your App > Event Subscriptions > Subscribe to Bot Events
Register the n8n webhook URL in Slack and subscribe to reaction events
Paste your n8n webhook URL into the 'Request URL' field on Slack's Event Subscriptions page. Slack immediately sends a challenge POST request — n8n must respond with the challenge value within 3 seconds or Slack rejects the URL. To handle this, add a 'Respond to Webhook' node in n8n right after the Webhook node and configure it to return the challenge. Under 'Subscribe to bot events', add the event 'reaction_added'.
- 1Paste your n8n Test URL into the 'Request URL' field
- 2In n8n, add a 'Code' node after the Webhook node temporarily to echo back the challenge — use: return [{json: {challenge: $input.first().json.challenge}}]
- 3Connect it to a 'Respond to Webhook' node set to 'First Incoming Item'
- 4Wait for Slack to show a green 'Verified' checkmark
- 5Under 'Subscribe to Bot Events', click 'Add Bot User Event'
- 6Search for and add 'reaction_added'
api.slack.com/apps > Your App > OAuth & Permissions > Bot Token Scopes
Add required OAuth scopes and install the app
Navigate to 'OAuth & Permissions' in your Slack app settings. Under 'Bot Token Scopes', add three scopes: channels:history (to fetch message content from the reacted message), reactions:read (to receive reaction events), and channels:read (to resolve channel names). After adding scopes, click 'Install to Workspace' and authorize the app. Copy the Bot User OAuth Token — you'll need it in n8n.
- 1Click 'OAuth & Permissions' in the left sidebar
- 2Under 'Bot Token Scopes', click 'Add an OAuth Scope'
- 3Add 'channels:history'
- 4Add 'reactions:read'
- 5Add 'channels:read'
- 6Scroll up and click 'Install to Workspace'
- 7Click 'Allow' on the authorization screen
- 8Copy the 'Bot User OAuth Token' (starts with xoxb-)
n8n Workflow Canvas > + Add Node > IF
Filter for the target emoji reaction
The reaction_added event fires for every reaction in every channel the bot can see — thumbs up, heart, everything. Add an 'IF' node in n8n to filter down to just your chosen emoji. The reaction name in Slack's API payload does not include colons — ':clipboard:' is sent as 'clipboard'. Wire the IF node so only matching reactions continue to the next step.
- 1Click the '+' connector after the Webhook node
- 2Search for 'IF' and add it
- 3Set Condition to 'String'
- 4Set Value 1 to expression: {{ $json.event.reaction }}
- 5Set Operation to 'Equal'
- 6Set Value 2 to your chosen emoji name without colons, e.g. clipboard
- 7Leave the 'False' branch unconnected or connect it to a 'No Operation' node
n8n Workflow Canvas > + Add Node > HTTP Request
Fetch the full Slack message content
The reaction_added event only gives you the message timestamp and channel ID — not the message text. You need to call Slack's conversations.history API to retrieve the actual message. Add an 'HTTP Request' node and configure it to call https://slack.com/api/conversations.history with the channel and timestamp parameters from the webhook payload. Include your Bot User OAuth Token as a Bearer token in the Authorization header.
- 1Add an 'HTTP Request' node after the IF node's true branch
- 2Set Method to 'GET'
- 3Set URL to 'https://slack.com/api/conversations.history'
- 4Under 'Query Parameters', add 'channel' = {{ $('Webhook').item.json.event.item.channel }}
- 5Add 'latest' = {{ $('Webhook').item.json.event.item.ts }}
- 6Add 'limit' = 1
- 7Add 'inclusive' = true
- 8Under 'Authentication', select 'Header Auth' and add Authorization: Bearer xoxb-your-token
n8n Workflow Canvas > + Add Node > Code
Parse the message and build the task payload
Add a 'Code' node to extract the message text, sender user ID, channel, and timestamp from the API response. You'll also format the Slack timestamp into a readable date here. The Code node lets you structure exactly the fields you want to send to Notion so the Notion node configuration stays clean.
- 1Add a 'Code' node after the HTTP Request node
- 2Set Language to 'JavaScript'
- 3Paste the transformation code from the Pro Tip section below
- 4Click 'Test Step' to verify the output fields look correct
n8n Workflow Canvas > + Add Node > Notion > Create Database Page
Connect Notion and create the database entry
Add a 'Notion' node and connect it with your Notion credentials (OAuth or Internal Integration Token). Set the operation to 'Create' and resource to 'Database Page'. Select your target Notion database from the dropdown — n8n will load all your accessible databases. Map each field from the Code node output to the corresponding Notion database property. At minimum, map the task title to the database's title property.
- 1Add a 'Notion' node after the Code node
- 2Click 'Credential for Notion API' and add your Internal Integration Token
- 3Set Resource to 'Database Page'
- 4Set Operation to 'Create'
- 5In the Database ID field, select your task database from the dropdown
- 6Click 'Add Property' for each field and map: Title = {{ $json.taskTitle }}, Status = 'To Do', Source = 'Slack'
- 7Add a 'Text' property for Slack Message URL mapped to {{ $json.messageUrl }}
n8n Workflow Canvas > + Add Node > HTTP Request
Add a Slack confirmation reaction back to the message
Add an HTTP Request node to post a reaction back to the original Slack message confirming the task was created. This closes the loop for the person who added the emoji — they see a ✅ appear on the message within seconds and know it was captured. Call the reactions.add API endpoint with the channel, timestamp, and your confirmation emoji.
- 1Add a second 'HTTP Request' node after the Notion node
- 2Set Method to 'POST'
- 3Set URL to 'https://slack.com/api/reactions.add'
- 4Set Body Content Type to 'JSON'
- 5Set Body to: { "channel": "{{ $('Code').item.json.channelId }}", "timestamp": "{{ $('Code').item.json.slackTimestamp }}", "name": "white_check_mark" }
- 6Use the same Bearer token Authorization header as in Step 6
channel: {{channel}}
ts: {{ts}}
n8n Workflow Canvas > IF Node > Respond to Webhook
Handle the Slack URL verification challenge permanently
Replace the temporary challenge-echo Code node from Step 3 with a proper IF node that detects whether the incoming request is a challenge verification or a real event. Slack sends challenge requests during URL registration and occasionally for verification checks. Route challenge requests to a Respond to Webhook node that returns the challenge value, and route real events through your main workflow logic.
- 1Add an IF node immediately after the Webhook trigger node
- 2Set Condition: check if {{ $json.type }} equals 'url_verification'
- 3On the 'true' branch, add a 'Respond to Webhook' node
- 4Set its Response Body to: { "challenge": "{{ $json.challenge }}" }
- 5On the 'false' branch, wire in your existing reaction filter IF node from Step 5
- 6Delete the temporary Code node you added in Step 3
n8n Workflow > Activate Toggle | api.slack.com > Event Subscriptions > Request URL
Switch to Production URL and activate the workflow
Go back to your Webhook trigger node and copy the Production URL (not the Test URL). Update the Request URL in Slack's Event Subscriptions page with this production URL. Slack will re-verify it — your workflow must be active for this to succeed. Click 'Active' toggle at the top of your n8n workflow to turn it on, then go to Slack and react to any message with your target emoji to do a live test.
- 1In n8n, click the Webhook node and copy the Production URL
- 2Go to api.slack.com/apps > your app > Event Subscriptions
- 3Replace the Test URL with your Production URL
- 4Wait for the green 'Verified' checkmark
- 5In n8n, click the 'Inactive' toggle in the top right to set it to 'Active'
- 6Go to Slack, find any message, and react with your chosen emoji
- 7Check your Notion database — the task should appear within 10 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 your team self-hosts and needs full control over the workflow logic or if you're already running n8n for other automations. The Code node in Step 7 is where n8n earns its place here — you can parse Slack's epoch timestamps, clean message text, handle edge cases like file attachments, and build deep-link URLs in one place with real JavaScript. The other reason to pick n8n: you can extend this workflow significantly without hitting per-task pricing. If you need this running for a 50-person team reacting to 200+ messages per month, n8n's self-hosted option costs you nothing per execution. The one scenario where you'd skip n8n: if nobody on your team has touched a workflow builder before and you need this working in 30 minutes. Zapier's Slack + Notion path has fewer steps to configure.
On n8n Cloud, this workflow costs roughly 5 executions per triggered reaction — the webhook receipt, the IF filter, the HTTP Request to Slack, the Code node, and the Notion create. At 200 reactions per month that's 1,000 executions. n8n Cloud's Starter plan gives you 5,000 executions per month for $20. Self-hosted n8n is free for unlimited executions if you run it on something like a $6/month DigitalOcean droplet. Zapier would run the same workflow at $19.99/month (Starter, 750 tasks) and hits its cap around 150 reactions/month. Make handles 1,000 operations for free, but Slack's reaction_added trigger requires a paid Make plan at $9/month — still cheaper than Zapier, but more expensive than self-hosted n8n.
Make's Slack module has a native 'Watch Reactions' trigger that handles the webhook verification automatically — no manual challenge-response setup. That's genuinely easier than n8n's manual webhook approach in Steps 2-3. Zapier has a 'New Reaction Added' Slack trigger that works out of the box in about 8 minutes with zero configuration. Power Automate has a Slack connector but it doesn't support reaction events at all — you'd need a workaround via a custom webhook. Pipedream has a pre-built Slack event source that handles scopes and verification for you, and its Node.js steps are comparable to n8n's Code node. n8n is still the right call if you're self-hosting or need the Code node's flexibility for message parsing — but if setup friction is your primary concern, Make's native trigger wins on ease.
Three things you'll hit after going live. First: Slack encodes special characters in message text — ampersands become &, less-than signs become <. Add a text cleanup step in your Code node using .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') before setting taskTitle. Second: Slack's retry behavior. If your n8n workflow takes more than 3 seconds to respond (common when Notion is slow), Slack sends the event again with an X-Slack-Retry-Num header — and you get duplicate tasks. Respond to Slack immediately with a 200, then do the processing. Third: Notion's API rate limit is 3 requests per second per integration. At normal team usage this never matters, but if you're bulk-testing the workflow by rapidly adding reactions, you'll see 429 errors from the Notion node. n8n doesn't automatically retry on 429 — add a Wait node with a 1-second delay before the Notion step if you're stress-testing.
Ideas for what to build next
- →Resolve Slack User IDs to Real Names — Add an HTTP Request node between the Code node and Notion node to call Slack's users.info API with the user ID, then map the display_name into a Notion Person or Text property so tasks show who requested them instead of U04KXYZ123.
- →Support Multiple Emoji Triggers for Task Types — Replace the single emoji IF filter with a Switch node that routes 📋 to 'Task', 🐛 to 'Bug', and ❓ to 'Question' — each branch creates a Notion page with a different Type property value, so your database is pre-categorized without anyone doing manual triage.
- →Send a Notion Page Link Back to Slack — After creating the Notion page, the API returns the new page URL — post it as a threaded reply on the original Slack message using chat.postMessage so the team can click directly into the Notion task from the conversation.
Related guides
How to Create Notion Tasks from Slack with Pipedream
~15 min setup
How to Create Notion Tasks from Slack with Power Automate
~15 min setup
How to Create Notion Tasks from Slack Messages with Zapier
~8 min setup
How to Create Notion Tasks from Slack Messages with Make
~12 min setup
How to Share Notion Meeting Notes to Slack with Pipedream
~15 min setup
How to Share Notion Meeting Notes to Slack with Power Automate
~15 min setup