-
Notifications
You must be signed in to change notification settings - Fork 5.5k
[TRIGGERS] Facebook Pages #17981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[TRIGGERS] Facebook Pages #17981
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Facebook Pages Webhook Sources | ||
|
||
This directory contains webhook sources for Facebook Pages events. These sources allow you to receive real-time notifications when various events occur on your Facebook Page. | ||
|
||
## Available Sources | ||
|
||
### 1. New Feed Activity (`new-feed-activity`) | ||
Emit new event when there's any new activity in your Facebook Page's feed. This includes new posts, comments, reactions, and shares. | ||
|
||
### 2. New Post to Page (`new-post`) | ||
Emit new event when a new post is made to your Facebook Page's feed. | ||
|
||
### 3. New Comment on Post (`new-comment`) | ||
Emit new event when a new comment is added to a post on your Facebook Page. | ||
|
||
### 4. New Reaction on Post (`new-reaction`) | ||
Emit new event when someone reacts to a post on your Facebook Page (likes, love, wow, etc.). | ||
|
||
### 5. New Share of Post (`new-share`) | ||
Emit new event when someone shares a post from your Facebook Page. | ||
|
||
### 6. Page Updated (`page-updated`) | ||
Emit new event when your Facebook Page information is updated (such as description, hours, location, etc.). | ||
|
||
### 7. New Message Received (`new-message`) | ||
Emit new event when your Facebook Page receives a new message via Messenger. | ||
|
||
## Setup Instructions | ||
|
||
To use these webhook sources, you need to: | ||
|
||
1. **Create a Facebook App**: | ||
- Go to [Facebook Developers](https://developers.facebook.com/) | ||
- Create a new app or use an existing one | ||
- Note your App ID | ||
|
||
2. **Configure Webhooks in Facebook**: | ||
- In your Facebook App dashboard, go to Webhooks | ||
- Subscribe to the "Page" object | ||
- When deploying a source in Pipedream, you'll get a webhook URL and verify token | ||
- Use these values in your Facebook webhook configuration | ||
|
||
3. **Set Required Permissions**: | ||
- For feed webhooks: `pages_manage_metadata` and `pages_show_list` | ||
- For message webhooks: `pages_messaging` | ||
|
||
4. **Subscribe Your Page**: | ||
- The webhook source will automatically subscribe your selected page to receive events | ||
- Make sure your page has not disabled the App platform in its settings | ||
|
||
## Common Properties | ||
|
||
All webhook sources share these properties: | ||
|
||
- **Facebook Pages App**: Your Facebook Pages connection | ||
- **Page**: The Facebook Page to monitor for events | ||
- **Verify Token**: A custom string for webhook verification (auto-generated but can be customized) | ||
|
||
## Event Data | ||
|
||
Each webhook event includes relevant data such as: | ||
- Event type and timestamp | ||
- User information (when available) | ||
- Content (messages, post text, etc.) | ||
- Related IDs (post_id, comment_id, etc.) | ||
|
||
## Troubleshooting | ||
|
||
1. **Webhook not receiving events**: | ||
- Ensure your Facebook App has the correct permissions | ||
- Verify the webhook is properly configured in Facebook | ||
- Check that your page has the app installed | ||
|
||
2. **Verification failing**: | ||
- Make sure the verify token matches exactly between Pipedream and Facebook | ||
- The webhook URL must be publicly accessible (HTTPS) | ||
|
||
3. **Missing events**: | ||
- Some events require specific permissions | ||
- Check Facebook's webhook documentation for limitations |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,112 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import crypto from "crypto"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import app from "../../facebook_pages.app.mjs"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export default { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
props: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
app, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
db: "$.service.db", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
http: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: "$.interface.http", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
customResponse: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
page: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
propDefinition: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
app, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"page", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
verifyToken: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: "string", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
label: "Verify Token", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: "A custom string you provide to Facebook for webhook verification. Facebook will send this token back when verifying your webhook endpoint.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
default: crypto.randomBytes(16).toString("hex"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hooks: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async activate() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Subscribe the page to the app with specified fields (page-level webhooks) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await this.app.createPageSubscription({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pageId: this.page, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
params: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
subscribed_fields: this.getFields().join(","), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Store page ID for deactivation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this._setPageId(this.page); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log(`Webhook URL: ${this.http.endpoint}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log(`Verify Token: ${this.verifyToken}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log("Subscribed page-level webhooks for fields:", this.getFields()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async deactivate() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const pageId = this._getPageId(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (pageId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await this.app.deletePageSubscription({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pageId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
methods: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
_getPageId() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return this.db.get("pageId"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
_setPageId(pageId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.db.set("pageId", pageId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
getFields() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw new Error("getFields is not implemented"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
generateMeta() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw new Error("generateMeta is not implemented"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
processEvent() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw new Error("processEvent is not implemented"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async run({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
query, body, method, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Handle webhook verification from Facebook | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (method === "GET") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const mode = query["hub.mode"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const token = query["hub.verify_token"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const challenge = query["hub.challenge"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (mode === "subscribe" && token === this.verifyToken) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log("Webhook verified"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.http.respond({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: 200, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
body: challenge, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log("Webhook verification failed"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.http.respond({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: 403, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Handle webhook events | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.http.respond({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: 200, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (body?.object === "page" && body?.entry) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
body.entry.forEach((entry) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (entry.changes) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.changes.forEach((change) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const eventData = this.processEvent(change); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (eventData) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const meta = this.generateMeta(eventData); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.$emit(eventData, meta); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+93
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling in event processing loop. The event processing should handle errors gracefully to prevent one malformed event from affecting others. // Handle webhook events
this.http.respond({
status: 200,
});
if (body?.object === "page" && body?.entry) {
body.entry.forEach((entry) => {
if (entry.changes) {
entry.changes.forEach((change) => {
- const eventData = this.processEvent(change);
- if (eventData) {
- const meta = this.generateMeta(eventData);
- this.$emit(eventData, meta);
- }
+ try {
+ const eventData = this.processEvent(change);
+ if (eventData) {
+ const meta = this.generateMeta(eventData);
+ this.$emit(eventData, meta);
+ }
+ } catch (error) {
+ console.error("Error processing event:", error, change);
+ }
});
}
});
} 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import common from "../common/webhook.mjs"; | ||
|
||
export default { | ||
...common, | ||
key: "facebook_pages-new-comment", | ||
name: "New Comment on Post", | ||
description: "Emit new event when a new comment is added to a post on your Facebook Page.", | ||
version: "0.0.1", | ||
type: "source", | ||
dedupe: "unique", | ||
methods: { | ||
...common.methods, | ||
getFields() { | ||
return [ | ||
"feed", | ||
]; | ||
}, | ||
generateMeta(data) { | ||
const { | ||
comment_id, parent_id, created_time, from, message, | ||
} = data; | ||
const ts = created_time | ||
? created_time * 1000 | ||
: Date.now(); | ||
const id = comment_id || `comment-${parent_id}-${ts}`; | ||
|
||
let summary = "New comment"; | ||
if (from?.name) { | ||
summary = `New comment by ${from.name}`; | ||
} | ||
if (message) { | ||
const preview = message.substring(0, 50); | ||
summary += `: ${preview}${message.length > 50 | ||
? "..." | ||
: ""}`; | ||
} | ||
|
||
return { | ||
id, | ||
summary, | ||
ts, | ||
}; | ||
}, | ||
processEvent(change) { | ||
if (change.field === "feed" && change.value) { | ||
const { | ||
item, verb, | ||
} = change.value; | ||
// Only emit events for new comments | ||
if (item === "comment" && verb === "add") { | ||
return change.value; | ||
} | ||
} | ||
return null; | ||
}, | ||
}, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for subscription creation.
The activation hook should handle potential failures when creating the page subscription to prevent storing invalid state.
📝 Committable suggestion
🤖 Prompt for AI Agents