Set up Instagram Webhooks
Webhooks let Instagram notify your server in real time. To set them up, you must expose an HTTPS endpoint that handles two request types: GET verification requests and POST event notifications.
hub.mode, hub.verify_token, and hub.challenge.What you’ll build
A single endpoint (example: /webhooks/instagram) that:
- Responds to a GET verification request by checking
hub.verify_tokenand returninghub.challenge. - Receives POST event payloads and returns 200 OK quickly, then processes events.
Step 1: Meta dashboard configuration
In your Meta App Dashboard, add the Webhooks product and configure:
- Callback URL: your HTTPS endpoint (example: https://yourdomain.com/webhooks/instagram)
- Verify Token: any secret string you choose (you must validate it on GET verification)
- Subscribe to the Instagram fields you need (e.g. messaging, comments, mentions, etc.)
When you click “Verify and Save”, Meta sends a GET request with hub.mode, hub.verify_token, hub.challenge. Your endpoint must validate the verify token and echo back the challenge.
Step 2: Node.js (Express) webhook endpoint
This is the simplest Node.js server example. Use this if you’re running a standalone server (not Next.js). Verification (GET) + events (POST) are handled on the same path.
import express from "express";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
app.use(express.json());
const VERIFY_TOKEN = process.env.IG_WEBHOOK_VERIFY_TOKEN; // set in env
// 1) Verification request (Meta sends this when you "Verify and Save")
app.get("/webhooks/instagram", (req, res) => {
const mode = req.query["hub.mode"];
const token = req.query["hub.verify_token"];
const challenge = req.query["hub.challenge"];
if (mode === "subscribe" && token === VERIFY_TOKEN) {
// ✅ Respond with challenge to confirm webhook
return res.status(200).send(challenge);
}
// ❌ Invalid verification token
return res.sendStatus(403);
});
// 2) Event notifications (Meta will POST events here)
app.post("/webhooks/instagram", (req, res) => {
// Always respond quickly
res.sendStatus(200);
// Process asynchronously
const body = req.body;
// Example: log raw payload
console.log("IG WEBHOOK EVENT:", JSON.stringify(body, null, 2));
// TODO: parse events and route to your handlers
});
//3) Privacy Policy
app.get("/privacy-policy", (req, res) => {
res.sendFile(path.join(__dirname, "privacy-policy.html"));
});
app.listen(3000, () => console.log("Webhook server running on :3000"));PRIVACY POLICY
privacy-policy.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Privacy Policy</title>
<style>
body {
font-family: system-ui, Segoe UI, Roboto, Arial;
max-width: 900px;
margin: 40px auto;
padding: 0 16px;
line-height: 1.6;
color: #111;
}
h1, h2 {
line-height: 1.2;
}
code {
background: #f2f2f2;
padding: 2px 6px;
border-radius: 6px;
}
.muted {
color: #444;
}
.card {
border: 1px solid #e5e5e5;
border-radius: 12px;
padding: 16px;
margin: 16px 0;
}
</style>
</head>
<body>
<h1>Privacy Policy</h1>
<p class="muted">Last updated: 2026-02-27</p>
<div class="card">
<h2>Overview</h2>
<p>
This application integrates with Instagram to enable messaging and webhook-based event handling.
We process only the data required to provide the service and improve reliability.
</p>
</div>
<div class="card">
<h2>Data We Collect</h2>
<ul>
<li>Webhook event payloads (e.g., message events, comment events, mention events) sent by Meta/Instagram</li>
<li>Technical metadata (timestamps, delivery status codes) for debugging and reliability</li>
</ul>
<p>
We do <strong>not</strong> sell your data.
</p>
</div>
<div class="card">
<h2>How We Use Data</h2>
<ul>
<li>To deliver messaging features and respond to events</li>
<li>To monitor errors and improve system stability</li>
<li>To prevent abuse and protect the service</li>
</ul>
</div>
<div class="card">
<h2>Storage & Retention</h2>
<p>
Webhook payloads may be temporarily logged for debugging. Logs are retained only as long as necessary
for operational troubleshooting and then deleted/rotated.
</p>
</div>
<div class="card">
<h2>Security</h2>
<p>
We use industry-standard security practices including HTTPS and restricted access controls.
Do not share your access tokens publicly.
</p>
</div>
<div class="card">
<h2>Your Choices</h2>
<ul>
<li>You may revoke the app’s access from your Meta/Instagram settings at any time</li>
<li>You may request deletion of stored logs related to your account</li>
</ul>
</div>
<div class="card">
<h2>Contact</h2>
<p>
If you have questions or deletion requests, contact:
<br />
<strong>Email:</strong> support@yourdomain.com
</p>
</div>
</body>
</html>Step 3: Understand event payloads
Instagram webhook events arrive as JSON (entries/changes). You should parse the payload and route it by field type. Meta provides examples of webhook notifications so you can model your parsing logic.
Production checklist
- Use HTTPS with a valid certificate (no self-signed).
- Keep your verify token secret; compare it exactly during verification.
- Return 200 quickly on POST; do heavy work async (queue / background job).
- Log safely (avoid dumping secrets/tokens).
Next.js-only setup
If you are building everything in Next.js (Route Handlers), use the dedicated Next.js setup component below.