Source:
ocean/docs/posthog-slack-integration.md| ✏️ Edit on GitHub
PostHog Slack Integration Guide
This guide covers integrating PostHog analytics with Slack for real-time notifications about user behavior, feature adoption, and business metrics.
Prerequisites
- PostHog account with admin access
- Slack workspace admin access
- Slack incoming webhooks enabled
Setting Up PostHog Webhooks
1. Create Slack Incoming Webhook
First, create a dedicated webhook for PostHog:
- Go to your Slack App configuration (or create a new app)
- Enable Incoming Webhooks
- Add a new webhook to workspace
- Select channel:
#alerts-analytics - Copy the webhook URL
2. Install PostHog Slack App
In PostHog:
-
Navigate to Apps in the sidebar
-
Search for "Slack"
-
Click "Install"
-
Configure the app:
{
"webhook_url": "YOUR_SLACK_WEBHOOK_URL",
"include_event_properties": true,
"format": "blocks"
}
Creating Analytics Alerts
User Signup Notifications
Monitor new user signups in real-time:
-
Go to Data Management → Actions
-
Click "New Action"
-
Configure:
- Name: "New User Signup"
- Match: Event name =
user_signed_up
-
Add Slack notification:
{
"channel": "#alerts-analytics",
"message": "🎉 New user signup: {{person.email}}",
"include_properties": ["plan", "referral_source", "organization_id"]
}
Feature Adoption Alerts
Track when users adopt key features:
// Example: First time using billing feature
posthog.capture('feature_first_use', {
feature: 'billing_dashboard',
user_id: user.id,
organization_id: org.id,
})
Configure PostHog Action:
{
"name": "Feature Adoption - Billing",
"match": {
"event": "feature_first_use",
"properties": {
"feature": "billing_dashboard"
}
},
"slack": {
"message": "💳 Organization {{organization_id}} accessed billing for the first time"
}
}
High-Value User Actions
Monitor important business events:
Action: 'High-Value Cart Created'
Conditions:
- Event: cart_updated
- Property: cart_value > 1000
Slack Message: '💰 High-value cart: ${{cart_value}} by {{person.email}}'
Channel: '#alerts-analytics'
Advanced Analytics Alerts
Conversion Funnel Alerts
Monitor funnel drop-offs:
-
Create a Funnel in PostHog:
- Step 1:
page_view(landing page) - Step 2:
signup_started - Step 3:
user_signed_up - Step 4:
onboarding_completed
- Step 1:
-
Set up alerts for significant drops:
// PostHog Webhook configuration
{
"funnel_id": "YOUR_FUNNEL_ID",
"alert_threshold": 0.7, // Alert if conversion < 70%
"check_interval": "hourly",
"slack_notification": {
"channel": "#alerts-analytics",
"message": "⚠️ Funnel conversion dropped below 70%: {{funnel_name}}"
}
}
Cohort-Based Alerts
Alert on specific user segments:
// Define cohort: "High-Value Users"
{
"cohort_definition": {
"name": "High-Value Users",
"filters": [
{ "property": "total_spent", "operator": ">", "value": 500 },
{ "property": "subscription_status", "value": "active" }
]
},
"alerts": {
"churn_risk": {
"condition": "no_activity_days > 14",
"slack": {
"message": "🚨 High-value user inactive: {{person.email}} ({{no_activity_days}} days)"
}
}
}
}
Feature Flag Monitoring
Alert on feature flag issues:
// Monitor feature flag performance
posthog.capture('feature_flag_evaluation', {
flag_key: 'new_checkout_flow',
variant: flag_variant,
error_occurred: error !== null,
load_time_ms: loadTime
})
// PostHog Action
{
"name": "Feature Flag Error Rate",
"conditions": {
"event": "feature_flag_evaluation",
"properties": {
"error_occurred": true
}
},
"aggregation": {
"type": "percentage",
"threshold": 5, // Alert if > 5% error rate
"window": "5m"
},
"slack": {
"message": "🚩 Feature flag '{{flag_key}}' has high error rate: {{error_percentage}}%"
}
}
Setting Up Business Metrics Alerts
Revenue Tracking
// Track revenue events
posthog.capture('purchase_completed', {
revenue: 99.99,
currency: 'USD',
product_id: 'pro_plan',
mrr_impact: 99.99
})
// Daily revenue summary
{
"schedule": "daily_9am",
"metric": "sum",
"event": "purchase_completed",
"property": "revenue",
"slack": {
"channel": "#alerts-analytics",
"message": "📊 Daily Revenue: ${{total_revenue}} ({{transaction_count}} transactions)"
}
}
User Engagement Metrics
// Weekly Active Users alert
{
"name": "Weekly Active Users Report",
"schedule": "weekly_monday_9am",
"query": {
"event": "$pageview",
"aggregation": "unique_users",
"date_range": "last_7_days"
},
"comparison": "previous_week",
"slack": {
"message": "📈 WAU: {{current_value}} ({{change_percentage}}% from last week)",
"include_chart": true
}
}
Retention Alerts
// Alert on retention drop
{
"name": "Retention Drop Alert",
"metric": "retention_rate",
"cohort": "new_users_last_month",
"threshold": {
"day_1": 80,
"day_7": 50,
"day_30": 30
},
"slack": {
"message": "📉 Retention below threshold: Day {{retention_day}} = {{retention_rate}}%"
}
}
Custom PostHog to Slack Integration
Create a more sophisticated integration using PostHog webhooks:
// supabase/functions/posthog-slack-webhook/index.ts
import { serve } from 'https://deno.land/std@0.208.0/http/server.ts'
interface PostHogEvent {
event: string
properties: Record<string, any>
timestamp: string
distinct_id: string
person?: {
email?: string
name?: string
}
}
const SLACK_WEBHOOKS = {
analytics: Deno.env.get('SLACK_WEBHOOK_ANALYTICS')!,
alerts: Deno.env.get('SLACK_WEBHOOK_ALERTS')!,
}
// Event routing configuration
const EVENT_ROUTES = {
// High-priority events
critical: {
events: ['payment_failed', 'subscription_cancelled', 'high_value_churn'],
webhook: SLACK_WEBHOOKS.alerts,
format: 'detailed',
},
// Analytics events
analytics: {
events: ['user_signed_up', 'feature_adopted', 'milestone_reached'],
webhook: SLACK_WEBHOOKS.analytics,
format: 'summary',
},
}
serve(async (req) => {
try {
const { event, properties, person } = (await req.json()) as PostHogEvent
// Determine routing
const route = Object.entries(EVENT_ROUTES).find(([_, config]) =>
config.events.includes(event)
)?.[1]
if (!route) {
return new Response('Event not configured for Slack', { status: 200 })
}
// Format message based on event type
const message = formatSlackMessage(event, properties, person, route.format)
// Send to Slack
await fetch(route.webhook, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message),
})
return new Response('OK', { status: 200 })
} catch (error) {
console.error('PostHog webhook error:', error)
return new Response('Error', { status: 500 })
}
})
function formatSlackMessage(
event: string,
properties: Record<string, any>,
person: any,
format: string
) {
const emoji = getEmojiForEvent(event)
const userName = person?.email || person?.name || properties.distinct_id || 'Unknown User'
if (format === 'detailed') {
return {
text: `${emoji} ${event.replace(/_/g, ' ').toUpperCase()}`,
blocks: [
{
type: 'header',
text: {
type: 'plain_text',
text: `${emoji} ${formatEventName(event)}`,
},
},
{
type: 'section',
fields: [
{
type: 'mrkdwn',
text: `*User:*\n${userName}`,
},
{
type: 'mrkdwn',
text: `*Time:*\n${new Date().toLocaleString()}`,
},
...Object.entries(properties)
.filter(([key]) => !['distinct_id', 'token'].includes(key))
.slice(0, 6)
.map(([key, value]) => ({
type: 'mrkdwn',
text: `*${formatPropertyName(key)}:*\n${value}`,
})),
],
},
],
}
}
// Simple format
return {
text: `${emoji} ${formatEventName(event)}: ${userName}`,
attachments: [
{
color: getColorForEvent(event),
fields: Object.entries(properties)
.filter(([key]) => ['revenue', 'plan', 'feature'].includes(key))
.map(([key, value]) => ({
title: formatPropertyName(key),
value: String(value),
short: true,
})),
},
],
}
}
function getEmojiForEvent(event: string): string {
const emojiMap: Record<string, string> = {
user_signed_up: '🎉',
payment_failed: '💔',
subscription_cancelled: '😢',
feature_adopted: '✨',
milestone_reached: '🏆',
high_value_churn: '🚨',
experiment_started: '🧪',
retention_improved: '📈',
}
return emojiMap[event] || '📊'
}
function formatEventName(event: string): string {
return event
.split('_')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ')
}
function formatPropertyName(prop: string): string {
return prop.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase())
}
function getColorForEvent(event: string): string {
if (event.includes('failed') || event.includes('error')) return 'danger'
if (event.includes('warning') || event.includes('churn')) return 'warning'
return 'good'
}
Slack App Commands
Create interactive Slack commands for PostHog data:
Slash Commands
Configure in your Slack app:
-
/analytics [metric]- Get quick metrics/analytics dau
> Daily Active Users: 1,234 (+5.2% from yesterday) -
/feature-flag [flag_name]- Check feature flag status/feature-flag new_checkout
> Feature Flag "new_checkout": 50% rollout, 234 users active -
/user-lookup [email]- Get user analytics/user-lookup user@example.com
> User: Premium plan, last seen 2h ago, 45 events today
Implementation
// Handle Slack slash commands
export async function handleSlackCommand(command: string, text: string) {
switch (command) {
case '/analytics':
return await getQuickMetric(text)
case '/feature-flag':
return await getFeatureFlagStatus(text)
case '/user-lookup':
return await getUserAnalytics(text)
default:
return { text: 'Unknown command' }
}
}
Best Practices
1. Alert Prioritization
- #alerts-critical: Payment failures, service outages
- #alerts-analytics: User milestones, daily summaries
- #alerts-experiments: A/B test results, feature flag updates
2. Message Formatting
Keep messages concise but informative:
Good: "🎉 New signup: john@example.com (Pro plan, Google referral)"
Bad: "Event user_signed_up occurred with properties..."
3. Rate Limiting
Prevent alert fatigue:
// Batch similar events
const eventBatcher = new Map()
function batchEvent(event: string, data: any) {
const batch = eventBatcher.get(event) || []
batch.push(data)
eventBatcher.set(event, batch)
// Send batched notification every 5 minutes
if (batch.length === 1) {
setTimeout(() => sendBatchedNotification(event), 5 * 60 * 1000)
}
}
4. Actionable Insights
Include next steps in alerts:
"📉 Signup conversion dropped to 45% (-10% from last week)
→ Check recent deployments
→ Review A/B test results
→ Analyze drop-off points"
Testing
1. Test Individual Events
// Test from your app
posthog.capture('test_slack_integration', {
test: true,
message: 'Testing PostHog to Slack integration',
timestamp: new Date().toISOString(),
})
2. Test Batch Processing
// Send multiple events to test batching
for (let i = 0; i < 10; i++) {
posthog.capture('batch_test_event', {
index: i,
batch_id: 'test_batch_001',
})
}
3. Test Error Scenarios
// Test error handling
posthog.capture('test_error_event', {
should_fail: true,
error_type: 'webhook_failure',
})
Troubleshooting
Common Issues
-
"Events not appearing in Slack"
- Verify webhook URL is correct
- Check PostHog action configuration
- Review PostHog logs for errors
-
"Too many notifications"
- Implement batching
- Add event filters
- Use sampling for high-volume events
-
"Missing event properties"
- Ensure properties are captured correctly
- Check property filters in actions
- Verify webhook payload format
Next Steps
- Set up custom dashboards in Slack using Block Kit
- Create scheduled reports for key metrics
- Implement two-way sync for user properties
- Build Slack bot for interactive analytics queries