Webhooks
Send annotation events to external services automatically
Overview
Webhooks allow you to receive annotation data at external URLs when users interact with annotations. This enables integrations with Slack, Discord, custom backends, CI/CD pipelines, and more.
Configure a webhook URL via the webhookUrl prop, and events will be sent automatically when annotations are created, updated, deleted, or submitted.
Configuration
Add the webhookUrl prop to enable webhooks:
import { Agentation } from "@alexgorbatchev/agentation";
function App() {
return (
<>
<YourApp />
<Agentation projectId="my-project" webhookUrl="https://your-server.com/webhook" />
</>
);
}With a webhook URL configured, you have two options: enable Auto-Send to fire events automatically, or click "Send Annotations" in the toolbar manually. When Auto-Send is on, the toolbar button is hidden.
Events
Webhooks fire for the following events:
annotation.add— New annotation createdannotation.delete— Annotation deletedannotation.update— Annotation comment editedannotations.clear— All annotations clearedsubmit— "Send Annotations" clicked
Webhook Payload
All events send a POST request with the following JSON structure:
{
"event": "annotation.add",
"timestamp": 1706234567890,
"url": "https://example.com/dashboard",
"annotation": {
"id": "1706234567890",
"comment": "Button is cut off on mobile",
"element": "button",
"elementPath": "body > main > form > button.submit-btn",
"timestamp": 1706234567890
}
}Event-specific payloads
annotation.add / annotation.delete / annotation.update
{
"event": "annotation.add",
"timestamp": 1706234567890,
"url": "https://example.com/page",
"annotation": { ... }
}annotations.clear
{
"event": "annotations.clear",
"timestamp": 1706234567890,
"url": "https://example.com/page",
"annotations": [ ... ]
}submit
{
"event": "submit",
"timestamp": 1706234567890,
"url": "https://example.com/page",
"output": "# Page Feedback\n\n...",
"annotations": [ ... ]
}Combining with Callbacks
You can use webhooks alongside the onSubmit and other callback props. Both will fire when events occur:
<Agentation
projectId="my-project"
webhookUrl="https://your-server.com/webhook"
onSubmit={(output, annotations) => {
// This fires in addition to the webhook
console.log("Submitted:", annotations.length, "annotations");
}}
onAnnotationAdd={(annotation) => {
// Track in analytics
analytics.track("annotation_created");
}}
/>Use Cases
Slack Notifications
// Server webhook handler
app.post("/webhook/agentation", async (req, res) => {
const { event, annotation, url } = req.body;
if (event === "annotation.add") {
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `New annotation on ${url}: "${annotation.comment}"`,
}),
});
}
res.json({ ok: true });
});GitHub Issue Creation
app.post("/webhook/agentation", async (req, res) => {
const { event, output, annotations } = req.body;
if (event === "submit" && annotations.length > 0) {
await fetch("https://api.github.com/repos/owner/repo/issues", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
title: `[Feedback] ${annotations.length} annotation(s)`,
body: output,
labels: ["feedback"],
}),
});
}
res.json({ ok: true });
});Real-time Dashboard
// Server with WebSocket broadcast
app.post("/webhook/agentation", (req, res) => {
const { event, annotation, url } = req.body;
// Broadcast to connected dashboard clients
wss.clients.forEach((client) => {
client.send(JSON.stringify({
type: "annotation_event",
event,
annotation,
url,
}));
});
res.json({ ok: true });
});Security Considerations
- Use HTTPS — Always use encrypted connections for webhook URLs
- Validate origin — Check the request origin if your webhook is public
- Rate limiting — Implement rate limits to prevent abuse
- Sanitize content — Annotation comments may contain user-generated content; sanitize before rendering
Testing Webhooks
Tools for testing webhooks during development:
- webhook.site — Free public endpoint for testing payloads
- ngrok — Expose local server for testing with real URLs
- RequestBin — Inspect and debug webhook payloads
Quick Test Setup
// Use webhook.site for testing
<Agentation projectId="my-project" webhookUrl="https://webhook.site/your-unique-id" />
// Then create annotations and check webhook.site for payloads