# How to Auto-DM Instagram Commenters for Free with n8n (Follow-Gate Included)

> Build your own ManyChat-style bot for $0 in software: when someone comments a keyword, n8n replies, checks if they follow you and DMs them the link. Workflow included.

- Source: https://plugstack.dev/instagram-comment-to-dm-n8n/
- Published by: PlugStack
- Last updated: 2026-09-25
- Author: Salohiddin Haitov

**ManyChat charges $29/month for this. You can run it yourself for $0 in software.** In this guide you’ll set up an n8n workflow that watches your Instagram comments, sends an automatic DM to anyone who comments a keyword, checks whether they follow you, and only then sends the link. It’s the same “comment GUIDE and I’ll DM it to you” flow big creators use – self-hosted, with no contact limits.

 

I built this for my own account ([@khaitov.dev](https://www.instagram.com/khaitov.dev/)) and it runs in production. Everything below is what actually worked, including the problems I hit and how to fix them.

 
 
[**Download the n8n workflow (JSON)**](https://drive.google.com/file/d/1NKNgC2xU-DaWLhxpxw0Ro1eS5dt8JaRJ/view?usp=sharing)
 
 

## What the workflow does

 
1. Someone comments a keyword (for example `GUIDE`) on any of your posts or Reels.
2. n8n receives the comment through Meta’s official webhook within seconds.
3. The bot replies publicly under the comment (“Sent! Check your DMs 📩”) and sends a private DM with a button.
4. When they tap the button, the bot checks whether they follow you.
5. **Following →** they get the link. **Not following →** they’re asked to follow first, then tap “I followed ✅” to get it.
6. Every step is counted, so you can see how many comments, clicks, new followers and links each keyword produced.

 

Extras built in:

 
- Keywords are case-insensitive: `guide`, `Guide!` and `GUIDE 🙏` all work.
- Several keywords can point to one link (handy for typos like `PROMT`).
- The same keyword can send a different link on a specific Reel.
- No duplicate DMs, even if Meta re-sends an event.
- The access token refreshes itself every week, so you never have to rotate it by hand.
- Normal DMs are left alone — the bot only reacts to its own keywords.

 

## Is it really free?

 

The software is. **n8n Community Edition is free to self-host** with unlimited executions, and Meta’s Instagram API costs nothing. What you need is somewhere to run n8n with a public HTTPS address:

 

| Option | Cost | Notes |
| --- | --- | --- |
| A server you already have | $0 | Fastest path — skip to Step 1. |
| [Oracle Cloud Always Free](https://www.youtube.com/watch?v=CndSt8d5utY) | $0 | Card required at sign-up; free capacity is sometimes unavailable in busy regions. |
| Small VPS (Hetzner, Contabo, etc.) | ~$4–6/month | The most reliable choice. |
| n8n Cloud | 14-day trial, then paid | No server work, but not free long-term. |

 
 
[YouTube Video | How to Setup N8N on Oracle Cloud Always free](https://www.youtube.com/watch?v=CndSt8d5utY)
 
 

Avoid free hosts that put your app to sleep when idle. Meta’s webhooks arrive late or fail, and comments get missed.

 

## What you’ll need

 
- An Instagram **professional account** (Creator or Business). Personal accounts can’t use the API.
- A free [Meta for Developers](https://developers.facebook.com/) account.
- n8n running on a public **HTTPS** domain (Meta rejects plain HTTP).
- A public privacy policy page on your website (needed in Step 6).
- About 45 minutes.

 

## Step 0 — Run n8n with Docker (skip if you already have it)

 

On a fresh Linux server with Docker installed, point a subdomain such as `n8n.yourdomain.com` at the server’s IP, then create these two files in an empty folder.

 

`docker-compose.yml`

 
 
   
 

```
services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    environment:
      - N8N_HOST=n8n.yourdomain.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.yourdomain.com/
      - GENERIC_TIMEZONE=UTC
      - N8N_PROXY_HOPS=1
      - EXECUTIONS_DATA_SAVE_ON_SUCCESS=all
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168
    volumes:
      - n8n_data:/home/node/.n8n

  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data

volumes:
  n8n_data:
  caddy_data:
Caddyfile

n8n.yourdomain.com {
    reverse_proxy n8n:5678
}
```

 
 

Start it with `docker compose up -d`. Caddy gets an SSL certificate automatically. Open `https://n8n.yourdomain.com` and create your owner account.

 

**Why these settings matter:** `WEBHOOK_URL` makes n8n show your real domain instead of `localhost` in webhook URLs. The `EXECUTIONS_DATA_*` lines keep a 7-day history of successful runs. Without them, only failed runs are saved, which makes testing confusing.

 

## Step 1 — Create the Meta app

 
1. Go to [developers.facebook.com/apps](https://developers.facebook.com/apps/) → **Create app**.
2. Choose the Instagram use case (the one for managing messages and content on Instagram). Meta renames these options from time to time; pick the one that mentions Instagram API.
3. Open **API setup with Instagram business login**.
4. In *Add required messaging permissions*, make sure these three are enabled: 
   - `instagram_business_basic`
   - `instagram_business_manage_comments`
   - `instagram_business_manage_messages`
5. In *Generate access tokens*, click **Add account** and log in with your Instagram professional account.
6. Copy two values: the **account ID** shown under your username (a long number starting with `1784…`) and the token from **Generate token**.

 

 
![Meta developer app showing Instagram business login access token and account ID for the n8n workflow](https://plugstack.dev/wp-content/uploads/2026/09/image-1024x430.webp)
 

⚠️ **Treat the token like a password.** Anyone who has it can send DMs from your account. Don’t paste it in chats, screenshots or public repos. If it leaks, remove the app under Instagram → Settings → Apps and websites, then generate a new token.

 

## Step 2 — Allow message access in Instagram

 

 
![Instagram settings with Allow access to messages turned on for API DM automation](https://plugstack.dev/wp-content/uploads/2026/09/image-1.webp)
 

In the Instagram app go to **Settings → Messages and story replies → Message controls → Connected tools** and turn on **Allow access to messages**. Without this, the API can’t send DMs.

 

## Step 3 — Import and configure the workflow

 
 
[**Download the n8n workflow (JSON)**](https://drive.google.com/file/d/1NKNgC2xU-DaWLhxpxw0Ro1eS5dt8JaRJ/view?usp=sharing)
 
 

 
![n8n workflow canvas for Instagram comment to DM automation with webhook, follow check and send DM nodes](https://plugstack.dev/wp-content/uploads/2026/09/image-2.webp)
 
1. In n8n: **Create workflow → ⋯ → Import from file** and pick the JSON you downloaded.
2. Open the **Config** node. It’s the only node you need to edit.

 
 
   
 

```
const CONFIG = {
  IG_USER_ID: '1784xxxxxxxxxxxx',        // account ID from Step 1
  ACCESS_TOKEN: 'IGAA...',               // token from Step 1
  VERIFY_TOKEN: 'any-long-random-string',// you'll paste this into Meta in Step 5
  API_VERSION: 'v23.0',
  ACCOUNT_HANDLE: '@your_handle',
  FAIL_OPEN: true,
  PUBLIC_REPLY: true,
  KEYWORDS: {
    GUIDE:  { title: 'free guide',  link: 'https://yoursite.com/guide' },
    PROMPT: { title: 'prompt pack', link: 'https://yoursite.com/prompts' },
  },
  ...
};
```

 
 

For `VERIFY_TOKEN` use something random. On macOS or Linux, `openssl rand -hex 16` generates one.

 
1. Click **Publish** (older n8n versions: toggle the workflow to **Active**).

 

**Check that it’s live.** Open this in your browser, with your own domain and verify token:

 

```
https://n8n.yourdomain.com/webhook/ig-dm?hub.mode=subscribe&hub.verify_token=YOUR_VERIFY_TOKEN&hub.challenge=test123
```

 

If the page shows `test123`, you’re ready for Meta.

 

## Step 4 — Understand the button and the fallback

 

Instagram only lets you check whether someone follows you *after they’ve interacted with your DMs* — a comment alone isn’t enough. That’s why the first DM includes a **“Send me the link”** button: tapping it gives the bot permission to check the follow and continue.

 

If Instagram ever rejects the button, the workflow automatically sends a text version instead: *“Reply YES and I’ll send you the link”*. Replying works exactly like tapping.

 

## Step 5 — Connect the Meta webhook

 
1. In your Meta app, open **Configure webhooks**.
2. **Callback URL:** `https://n8n.yourdomain.com/webhook/ig-dm`
3. **Verify token:** the same `VERIFY_TOKEN` from the Config node.
4. Click **Verify and save**.
5. Under *Webhook fields*, subscribe to `comments`, `messages` and `messaging_postbacks`.
6. Make sure **Webhook subscription** is **On** for your account in the token section.

 

 
![](https://plugstack.dev/wp-content/uploads/2026/09/image-3-1024x470.webp)
 

Click **Test** next to the `comments` field. A new execution should appear in n8n → **Executions**. Meta’s test event contains no keyword, so nothing gets sent — that’s expected.

 

## Step 6 — Switch the app to Live (the step everyone misses)

 

This is where I lost the most time. **While the app is in Development mode, Meta does not send you comments from other people.** Meta’s Test button works, but your followers’ comments never arrive. The comments API even shows `comments_count: 3` while returning an empty list.

 

You do **not** need App Review when you only use your own account. You only need to fill in the basics and switch to Live:

 
1. **App settings → Basic:** add your **Privacy Policy URL**, a **User data deletion** instructions URL (a section on the same page is fine), a **category**, an **app icon** (1024×1024) and a contact email. Save.
2. Switch **App Mode** from Development to **Live** (in newer dashboards: **Publish** in the left menu).

 
![](https://plugstack.dev/wp-content/uploads/2026/09/image-4.webp)
 

Your privacy policy must be publicly reachable. Open it in a private window to check, and if you use Cloudflare, make sure Bot Fight Mode isn’t blocking Meta’s crawler. It should say what Instagram data you receive (user ID, username, comment/message text, follow status), why, how long you keep it, and how people can ask for deletion.

 

## Step 7 — Test it for real

 
1. From a **different** Instagram account, comment your keyword on any of your posts. Comments from your own account are ignored on purpose, so the bot never answers itself.
2. Within seconds you should see the public reply and a DM on the test account.
3. Tap **Send me the link**. If the test account doesn’t follow you, you’ll get the follow-first message. Follow, tap **I followed ✅**, and the link arrives.

 

## See your stats

 

Open this URL (bookmark it, and don’t share it — it contains your verify token):

 

```
https://n8n.yourdomain.com/webhook/ig-dm?stats=YOUR_VERIFY_TOKEN
```

 

| Field | Meaning |
| --- | --- |
| `comments` | Comments that contained the keyword |
| `clicks` | People who tapped the button or replied YES |
| `followGate` | People asked to follow first — roughly your new followers from this keyword |
| `links` | People who received the link |
| `tokenRefreshedAt` | Last automatic token refresh (fills in after the first week) |
| `lastEvents` | The 30 most recent events (times in UTC) |

 

## Customizing

 

### Add a keyword for a new Reel

 

Add one line to `KEYWORDS` and click **Publish**:

 

```
PRICING: { title: 'freelance pricing sheet', link: 'https://yoursite.com/pricing' },
```

 

Tip: use a different keyword for each Reel. Your stats then show which video brought the leads.

 

### Several keywords, one link (typos included)

 

Define the resource once, above `const CONFIG = {`, and reuse it:

 

```
const PROMPT_PACK = { title: 'prompt pack', link: 'https://yoursite.com/prompts' };

// inside KEYWORDS:
PROMPT:  PROMPT_PACK,
PROMPTS: PROMPT_PACK,
PROMT:   PROMPT_PACK,
```

 

Matching uses whole words, so add plural forms separately.

 

### Same keyword, different link on one Reel

 

Use `POSTS` with the Reel’s media ID. Everything else falls back to `KEYWORDS`:

 

```
POSTS: {
  '17900000000000000': { GUIDE: { title: 'bonus guide', link: 'https://yoursite.com/bonus' } },
},
```

 

To list your media IDs, open this URL with your token:

 

```
https://graph.instagram.com/v23.0/me/media?fields=id,caption&access_token=YOUR_TOKEN
```

 

### Change the wording

 

All DM texts live in the `TEXT` block of the Config node, and the public replies in `PUBLIC_REPLIES`. Keep several public-reply variations so they don’t look spammy. Set `PUBLIC_REPLY: false` to turn public replies off.

 

## Limits you should know

 
- **750 comment DMs per hour** per account. This is Meta’s cap on private replies to post and Reel comments. Follow-up messages (the follow-gate and the link) allow up to 100 per second.
- **One private reply per comment, within 7 days.** After that, you can keep messaging only if the person replies (a 24-hour window).
- **No contact limits.** Unlike ManyChat’s plans, the number of people isn’t capped. Only Meta’s API rate limits apply.
- If you ever go over 750 per hour on one viral Reel, the extra commenters won’t get a DM from this version. Add a queue if you expect that volume.

 

## Troubleshooting

 

| Symptom | Cause and fix |
| --- | --- |
| Meta says the callback URL couldn’t be validated | Workflow not published, verify token doesn’t match, or the URL isn’t HTTPS with a valid certificate. |
| Production URL shows `localhost:5678` | Set `WEBHOOK_URL` in your n8n environment and restart. |
| `404 webhook is not registered` | The workflow isn’t published, or an older copy still uses the `ig-dm` path. Unpublish or delete the old one. |
| Error: “Unused Respond to Webhook node found” | You’re using an old copy of the workflow. Re-download the current JSON; the POST webhook now answers Meta through its own *Ack 200* node. |
| Meta’s Test works, real comments never arrive | The app is in Development mode. Complete Step 6. |
| Executions list stays empty but DMs are sent | n8n isn’t saving successful runs. Workflow ⋯ → Settings → *Save successful production executions*, or set `EXECUTIONS_DATA_SAVE_ON_SUCCESS=all`. |
| Nothing happens when you comment | You commented from your own account (ignored by design), or the keyword didn’t match. |
| Execution runs but no DM arrives | Check “Allow access to messages” (Step 2), then open the *Send Private Reply* node in the execution to read Meta’s error. |
| Stats and token refresh don’t save | n8n only stores this data in production runs of a published workflow, not when you click “Execute” manually. |

 

## FAQ

 
 

### ### Will Instagram ban my account for this?

 

The workflow uses Meta’s official Instagram API — the same one ManyChat and similar tools use — and only messages people who commented your keyword. Keep the messages useful, don’t spam, and follow Meta’s platform policies.

 
 
 
 

### ### Do I have to go through App Review?

 

No, as long as you only connect Instagram accounts you own or manage. App Review is required if you offer this as a service to other people’s accounts.

 
 
 
 

### ### Does the token expire?

 

Long-lived tokens last 60 days. The workflow refreshes yours every 7 days, so it never expires as long as n8n stays online. If your server is down for more than 60 days, or you remove the app from Instagram, generate a new token and paste it into the Config node.

 
 
 
 

### ### Can I use it for several Instagram accounts?

 

Yes, but a Meta app has a single webhook callback URL. The simplest setup is one Meta app per Instagram account: import the workflow once per account, change the webhook path in both webhook nodes (for example `ig-dm-2`), and point that account’s app to the matching URL.

 
 
 

 

**Got it running?** Show me tag [@khaitov.dev](https://www.instagram.com/khaitov.dev/) on Instagram. I share free tools and dev workflows like this every week.

 

Stuck on the server part, or want this set up for your account? [Get in touch](https://plugstack.dev/contact/).
