PostHog GitHub Continuous AI
This guide introduces how to integrate PostHog and GitHub to build continuous product analytics and AI-driven decision-making systems.
Overview
By combining PostHog's product analytics capabilities with GitHub's code management, ByteBuddy can:
- Automatically analyze user behavior data
- Generate product improvement recommendations based on data
- Create data-driven Issues and PRs
- Monitor feature performance after release
Configuration
1. Install Required MCP Servers
bash
npm install -g posthog-mcp-server github-mcp-server2. Configure ByteBuddy
json
{
"mcpServers": {
"posthog": {
"command": "node",
"args": ["posthog-mcp-server"],
"env": {
"POSTHOG_API_KEY": "your-posthog-api-key",
"POSTHOG_HOST": "https://app.posthog.com"
}
},
"github": {
"command": "node",
"args": ["github-mcp-server"],
"env": {
"GITHUB_TOKEN": "your-github-token"
}
}
}
}Use Cases
Scenario 1: Automated Product Insights
typescript
// Product insights automation
class ProductInsights {
async generateWeeklyInsights() {
// Get data from the past week
const weeklyData = await mcp.call("posthog.getEvents", {
events: ["$pageview", "$autocapture"],
date_from: "-7d",
date_to: "now",
properties: [],
});
// Analyze key metrics
const insights = await this.analyzeKeyMetrics(weeklyData);
// Generate improvement recommendations
const recommendations = await this.generateRecommendations(insights);
// Create GitHub Issues
for (const recommendation of recommendations) {
await this.createInsightIssue(recommendation);
}
return insights;
}
private async analyzeKeyMetrics(data: any) {
return {
userEngagement: this.calculateEngagement(data),
featureUsage: this.analyzeFeatureUsage(data),
conversionRates: this.calculateConversionRates(data),
dropOffPoints: this.identifyDropOffPoints(data),
performance: this.analyzePerformance(data),
};
}
private async generateRecommendations(insights: any) {
const recommendations = [];
// User engagement analysis
if (insights.userEngagement.score < 0.7) {
recommendations.push({
title: "Improve User Engagement",
description: `Current user engagement score is ${insights.userEngagement.score}, below target value`,
type: "enhancement",
priority: "high",
suggestedActions: [
"Optimize homepage loading speed",
"Improve user onboarding flow",
"Add personalized recommendations",
],
});
}
// Feature usage analysis
const lowUsageFeatures = insights.featureUsage.filter((f) => f.usage < 0.1);
for (const feature of lowUsageFeatures) {
recommendations.push({
title: `Low Usage of Feature ${feature.name}`,
description: `Feature ${feature.name} usage is only ${(feature.usage * 100).toFixed(2)}%`,
type: "enhancement",
priority: "medium",
suggestedActions: [
"Improve feature visibility",
"Add feature usage guidance",
"Collect user feedback",
],
});
}
return recommendations;
}
private async createInsightIssue(recommendation: any) {
const issueBody = this.generateIssueBody(recommendation);
return await mcp.call("github.createIssue", {
owner: "your-org",
repo: "your-repo",
title: recommendation.title,
body: issueBody,
labels: ["data-driven", recommendation.type, recommendation.priority],
assignees: this.findAssignees(recommendation.type),
});
}
}Scenario 2: A/B Test Analysis
typescript
// A/B test automated analysis
class ABTestAnalysis {
async analyzeABTest(testId: string) {
// Get test data
const testData = await mcp.call("posthog.getExperimentResults", {
experiment_id: testId,
date_from: "-30d",
date_to: "now",
});
// Statistical analysis
const analysis = this.performStatisticalAnalysis(testData);
// Generate report
const report = await this.generateTestReport(testId, analysis);
// If test has clear results, automatically create PR
if (analysis.winner) {
await this.createWinnerPR(testId, analysis.winner);
}
return report;
}
private performStatisticalAnalysis(testData: any) {
// Calculate statistical significance
const variants = testData.variants.map((variant) => ({
name: variant.key,
conversionRate: variant.conversion_rate,
sampleSize: variant.participants,
confidence: this.calculateConfidence(variant),
uplift: this.calculateUplift(variant, testData.control),
}));
// Determine winner
const winner = this.determineWinner(variants);
return {
variants,
winner,
statisticalSignificance: this.isStatisticallySignificant(testData),
testDuration: this.calculateTestDuration(testData),
recommendations: this.generateTestRecommendations(variants),
};
}
private async createWinnerPR(testId: string, winner: any) {
const prTitle = `Implement winning variant: ${winner.name} for test ${testId}`;
const prBody = this.generatePRBody(testId, winner);
return await mcp.call("github.createPullRequest", {
owner: "your-org",
repo: "your-repo",
title: prTitle,
body: prBody,
head: `feature/test-${testId}-${winner.name}`,
base: "main",
});
}
}Scenario 3: User Feedback Integration
typescript
// User feedback automated processing
class UserFeedbackProcessor {
async processFeedback() {
// Get recent feedback
const feedback = await mcp.call("posthog.getSurveyResponses", {
survey_id: "user-satisfaction",
date_from: "-7d",
});
// Analyze feedback trends
const trends = await this.analyzeFeedbackTrends(feedback);
// Create issues or improvement tasks
for (const trend of trends) {
if (trend.severity === "high") {
await this.createFeedbackIssue(trend);
}
}
return trends;
}
private async analyzeFeedbackTrends(feedback: any[]) {
// Use sentiment analysis
const sentimentAnalysis = await this.performSentimentAnalysis(feedback);
// Identify common issues
const commonIssues = this.identifyCommonIssues(feedback);
// Trend analysis
const trends = [];
for (const issue of commonIssues) {
if (issue.count > 5) {
trends.push({
issue: issue.description,
count: issue.count,
sentiment: sentimentAnalysis[issue.description],
severity: this.calculateSeverity(
issue.count,
sentimentAnalysis[issue.description],
),
affectedUsers: issue.users.length,
});
}
}
return trends;
}
private async createFeedbackIssue(trend: any) {
const issueBody = `
## User Feedback Trend Analysis
**Issue Description**: ${trend.issue}
**Affected Users**: ${trend.affectedUsers}
**Feedback Count**: ${trend.count}
**Sentiment Analysis**: ${trend.sentiment.label} (Confidence: ${trend.sentiment.confidence})
**Severity**: ${trend.severity}
## Recommended Actions
1. Investigate specific user scenarios
2. Develop solutions
3. Track improvement effectiveness
## Related Data
- PostHog Dashboard: [View detailed data](https://app.posthog.com/insights)
- User feedback records: Exported to attachment
`;
return await mcp.call("github.createIssue", {
owner: "your-org",
repo: "your-repo",
title: `User Feedback: ${trend.issue}`,
body: issueBody,
labels: ["user-feedback", trend.severity, "data-driven"],
});
}
}Continuous Monitoring
1: Performance Monitoring
typescript
// Product performance monitoring
class PerformanceMonitor {
async monitorProductHealth() {
const healthChecks = [
this.checkPageLoadTimes(),
this.checkErrorRates(),
this.checkUserSatisfaction(),
this.checkFeaturePerformance(),
];
const results = await Promise.allSettled(healthChecks);
const healthReport = {
overall: "healthy",
metrics: {},
alerts: [],
};
results.forEach((result, index) => {
const metricName = [
"pageLoad",
"errorRate",
"userSatisfaction",
"featurePerformance",
][index];
if (result.status === "fulfilled") {
healthReport.metrics[metricName] = result.value;
if (result.value.status !== "healthy") {
healthReport.alerts.push({
metric: metricName,
severity: result.value.severity,
message: result.value.message,
});
}
}
});
// If there are alerts, create Issue
if (healthReport.alerts.length > 0) {
await this.createHealthAlert(healthReport);
}
return healthReport;
}
private async checkPageLoadTimes() {
const performanceData = await mcp.call("posthog.getInsight", {
insight_id: "page-load-times",
date_from: "-24h",
});
const avgLoadTime = performanceData.result[0].value;
return {
status: avgLoadTime < 3000 ? "healthy" : "warning",
value: avgLoadTime,
threshold: 3000,
message: `Average page load time: ${avgLoadTime}ms`,
};
}
private async createHealthAlert(healthReport: any) {
const alertBody = `
## Product Health Status Alert
**Overall Status**: ${healthReport.overall}
### Key Metrics
${Object.entries(healthReport.metrics)
.map(
([key, value]: [string, any]) =>
`- **${key}**: ${value.message} (${value.status})`,
)
.join("\n")}
### Alert Details
${healthReport.alerts
.map(
(alert) =>
`- **${alert.metric}**: ${alert.message} (Severity: ${alert.severity})`,
)
.join("\n")}
### Recommended Actions
1. Immediately investigate high-severity issues
2. Develop improvement plans
3. Increase monitoring frequency
---
*This alert was automatically generated by ByteBuddy*
`;
return await mcp.call("github.createIssue", {
owner: "your-org",
repo: "your-repo",
title: "Product Health Status Alert",
body: alertBody,
labels: ["health-alert", "automated", "monitoring"],
});
}
}Automated Workflows
1: Daily Reports
typescript
// Automated daily reporting
class DailyReporter {
async generateDailyReport() {
const reportDate = new Date().toISOString().split("T")[0];
// Collect data
const data = {
analytics: await this.getAnalyticsData(),
github: await this.getGitHubActivity(),
errors: await this.getErrorData(),
performance: await this.getPerformanceData(),
};
// Generate report
const report = await this.compileReport(data, reportDate);
// Publish to GitHub
await this.publishReport(report, reportDate);
// Send notification
await this.sendSummary(report);
return report;
}
private async getAnalyticsData() {
return await mcp.call("posthog.getInsight", {
insight_id: "daily-overview",
date_from: "-1d",
date_to: "now",
});
}
private async publishReport(report: any, date: string) {
const reportPath = `reports/daily-${date}.md`;
// Create or update report file
await mcp.call("github.createOrUpdateFile", {
owner: "your-org",
repo: "your-repo",
path: reportPath,
message: `Daily report for ${date}`,
content: report.content,
branch: "main",
});
// Create Issue to discuss report
await mcp.call("github.createIssue", {
owner: "your-org",
repo: "your-repo",
title: `Daily Report - ${date}`,
body: `## Daily Report Summary
${report.summary}
[View detailed report](https://github.com/your-org/your-repo/blob/main/${reportPath})
### Key Metrics
${report.keyMetrics
.map((metric) => `- **${metric.name}**: ${metric.value} (${metric.trend})`)
.join("\n")}
`,
labels: ["daily-report", "automated"],
});
}
}Best Practices
1: Data Quality Assurance
typescript
// Data quality checking
class DataQualityChecker {
async checkDataQuality() {
const checks = [
this.checkDataCompleteness(),
this.checkDataAccuracy(),
this.checkDataConsistency(),
this.checkDataTimeliness(),
];
const results = await Promise.allSettled(checks);
const qualityReport = {
overall: "good",
issues: [],
recommendations: [],
};
results.forEach((result, index) => {
if (
result.status === "rejected" ||
(result.status === "fulfilled" && !result.value.passed)
) {
qualityReport.issues.push({
check: ["completeness", "accuracy", "consistency", "timeliness"][
index
],
issue: result.reason || result.value.issue,
});
}
});
return qualityReport;
}
}Through deep integration of PostHog and GitHub, ByteBuddy can build powerful data-driven decision-making systems, making product development more intelligent and efficient.