site/docs/providers/slack.md
The Slack provider enables human-in-the-loop evaluations by sending prompts to Slack channels or users and collecting responses. This is useful for:
The Slack provider requires the @slack/web-api package to be installed separately:
npm install @slack/web-api
:::note This is an optional dependency and only needs to be installed if you want to use the Slack provider. :::
Create a Slack App
Configure Bot Token Scopes
chat:write - to send messageschannels:history - to read public channel messagesgroups:history - to read private channel messagesim:history - to read direct messageschannels:read - to access public channel informationgroups:read - to access private channel informationim:read - to access direct message informationNote: All scopes are required for the provider to work properly across different channel types.
Install App to Workspace
xoxb-)Invite Bot to Channel
/invite @YourBotNameexport SLACK_BOT_TOKEN="xoxb-your-bot-token"
providers:
- id: slack
config:
channel: 'C0123456789' # Your channel ID
The Slack provider supports multiple formats:
# Basic format with channel in config
providers:
- id: slack # Uses SLACK_BOT_TOKEN env var
config:
# token: "{{ env.SLACK_BOT_TOKEN }}" # optional, auto-detected
channel: "C0123456789"
# Short format - channel ID directly in provider string
providers:
- slack:C0123456789
# Explicit channel format
providers:
- slack:channel:C0123456789
# Direct message to a user
providers:
- slack:user:U0123456789
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
token | string | Yes* | SLACK_BOT_TOKEN env var | Slack Bot User OAuth Token |
channel | string | Yes | - | Channel ID (C...) or User ID (U...) |
responseStrategy | string | No | 'first' | How to collect responses: 'first', 'user', or 'timeout' |
waitForUser | string | No | - | User ID to wait for (when using 'user' strategy) |
timeout | number | No | 60000 | Timeout in milliseconds |
includeThread | boolean | No | false | Include thread timestamp in output metadata |
formatMessage | function | No | - | Custom message formatting function |
threadTs | string | No | - | Thread timestamp to reply in |
*Token is required either in config or as environment variable
Captures the first non-bot message after the prompt:
providers:
- id: slack
config:
channel: 'C0123456789'
responseStrategy: 'first'
Waits for a response from a specific user:
providers:
- id: slack
config:
channel: 'C0123456789'
responseStrategy: 'user'
waitForUser: 'U9876543210'
Collects all responses until timeout:
providers:
- id: slack
config:
channel: 'C0123456789'
responseStrategy: 'timeout'
timeout: 300000 # 5 minutes
C... - Public channelsG... - Private channels/groupsD... - Direct messagesW... - Shared/Connect channelsdescription: Collect human feedback on AI responses
providers:
- id: openai:gpt-5
- id: slack:C0123456789
config:
timeout: 300000 # 5 minutes
prompts:
- 'Explain {{topic}} in simple terms'
tests:
- vars:
topic: 'quantum computing'
- vars:
topic: 'machine learning'
- vars:
topic: 'blockchain technology'
# Run with: promptfoo eval -j 1
description: Get expert feedback from specific team member
providers:
- id: slack
config:
channel: 'C0123456789'
responseStrategy: 'user'
waitForUser: 'U9876543210' # Expert's user ID
timeout: 600000 # 10 minutes
prompts:
- file://prompts/technical-review.txt
tests:
- vars:
code: |
def factorial(n):
if n == 0:
return 1
return n * factorial(n-1)
description: Continue conversation in thread
providers:
- id: slack
config:
channel: 'C0123456789'
threadTs: '1234567890.123456' # Existing thread
includeThread: true
prompts:
- 'Follow-up question: {{question}}'
// promptfooconfig.js
module.exports = {
providers: [
{
id: 'slack',
config: {
channel: 'C0123456789',
formatMessage: (prompt) => {
return `🤖 *AI Evaluation Request*\n\n${prompt}\n\n_Please provide your feedback_`;
},
},
},
],
};
Concurrency: Run Slack evaluations with -j 1 to ensure messages are sent sequentially
promptfoo eval -j 1
Timeouts: Set appropriate timeouts based on expected response time
Channel Selection:
Message Formatting:
Rate Limits: Be aware of Slack's rate limits
The Slack provider is excellent for testing other Slack bots in their native environment. This allows you to:
Invite both bots to a test channel:
/invite @your-bot-to-test
/invite @provider
Configure the provider to mention the target bot:
providers:
- id: slack
config:
channel: C123456789
timeout: 10000
responseStrategy: first
# Optional: format messages to mention the bot
messageFormatter: |
@your-bot-to-test {{prompt}}
Filter responses to only capture the target bot:
providers:
- id: slack
config:
channel: C123456789
timeout: 10000
responseStrategy: user
userId: U_YOUR_BOT_ID # The bot's user ID
description: Test our customer support bot
providers:
- id: slack
label: support-bot-test
config:
channel: C_TEST_CHANNEL
timeout: 15000
responseStrategy: user
userId: U_SUPPORT_BOT_ID
messageFormatter: |
<@U_SUPPORT_BOT_ID> {{prompt}}
prompts:
- 'How do I reset my password?'
- 'What are your business hours?'
- 'I need to speak to a human'
- "My order hasn't arrived yet, order #12345"
tests:
- vars:
expected_intent: password_reset
assert:
- type: contains
value: 'reset'
- type: contains
value: 'password'
- vars:
expected_intent: business_hours
assert:
- type: contains-any
value: ['hours', 'open', 'closed', 'Monday', 'schedule']
- vars:
expected_intent: human_handoff
assert:
- type: contains-any
value: ['agent', 'representative', 'transfer', 'human']
- vars:
expected_intent: order_status
assert:
- type: contains
value: '12345'
- type: javascript
value: |
// Check if bot asked for more info or provided status
return output.includes('track') || output.includes('status') || output.includes('delivery');
Test conversation flows by chaining prompts:
prompts:
- "Hi, I'd like to order a pizza"
- 'Yes, I want a large pepperoni'
- 'My address is 123 Main St'
Test how the bot handles invalid inputs:
prompts:
- 'HELP ME NOW!!!!!!'
- 'asdfghjkl'
- "' OR 1=1 --"
- ''
Use multiple parallel evaluations to test bot performance:
promptfoo eval -c bot-test-config.yaml -j 10
Compare multiple bot implementations:
providers:
- id: slack
label: bot-v1
config:
channel: C_CHANNEL_V1
userId: U_BOT_V1
- id: slack
label: bot-v2
config:
channel: C_CHANNEL_V2
userId: U_BOT_V2
prompts:
- "What's your return policy?"
assert:
- type: llm-rubric
value: 'Response should be helpful, accurate, and mention the 30-day return window'
To find a bot's user ID:
// Run this in your test channel
const { WebClient } = require('@slack/web-api');
const client = new WebClient(process.env.SLACK_BOT_TOKEN);
async function findBotId() {
const members = await client.conversations.members({
channel: 'C_YOUR_CHANNEL',
});
for (const userId of members.members) {
const user = await client.users.info({ user: userId });
if (user.user.is_bot) {
console.log(`Bot: ${user.user.name} - ID: ${userId}`);
}
}
}
channels:history permission# Human evaluation of customer service responses
description: Compare AI and human customer service responses
providers:
- id: openai:gpt-5
config:
temperature: 0.7
- id: anthropic:messages:claude-sonnet-4-5-20250929
- id: slack:C0123456789
config:
responseStrategy: 'first'
timeout: 180000 # 3 minutes
formatMessage: (prompt) =>
`📋 *Customer Service Evaluation*\n\n${prompt}\n\n_How would you respond to this customer?_`
prompts:
- |
Customer message: "{{message}}"
Please provide a helpful and empathetic response.
tests:
- vars:
message: "I've been waiting for my order for 2 weeks and no one is responding to my emails!"
assert:
- type: llm-rubric
value: Response acknowledges delay and provides concrete next steps
- vars:
message: 'The product I received is damaged and I need a replacement'
assert:
- type: llm-rubric
value: Response offers immediate solution and apologizes for inconvenience
- vars:
message: 'How do I upgrade my subscription plan?'
assert:
- type: contains
value: upgrade
# Run evaluation
# promptfoo eval -j 1 --no-progress-bar
Create a test channel in Slack
Invite your bot to the channel: /invite @YourBotName
Create a simple test config:
providers:
- id: slack:YOUR_CHANNEL_ID
config:
timeout: 30000
prompts:
- "Test message - please reply with 'success'"
tests:
- assert:
- type: contains
value: success
Run: npx promptfoo eval -j 1
Reply in Slack within 30 seconds
/invite @YourBotName