Instagram Webhooks (Node.js + Next.js)

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.

Your webhook URL must be HTTPS with a valid certificate (self-signed certs are not supported). Webhook verification uses 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_token and returning hub.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.

Reference: Instagram Platform Webhooks docs and Meta Webhooks verification flow.