Skip to content
 
 

Repository files navigation


Someone comments "guide" on your reel. They get a DM with your link, automatically, about two seconds later.

That is the entire product. Tools that do this start around $15/month and want your Instagram login on their servers. This is the same thing, running on your Cloudflare account, on the free tier, for $0 β€” and you can read all 4,400 lines of it in an afternoon.

Deploy to Cloudflare Workers    npm run setup


Why this exists

  Hosted tools Comment to DM
Cost $15–99 / month, forever $0. Cloudflare's free tier covers 100,000 requests a day.
Your Instagram token On their servers, alongside everyone else's In your Cloudflare account, encrypted with AES-256-GCM using a key only you hold
Your audience's DMs Pass through a third party Go straight from your Worker to Meta
If they shut down You lose the automation Nothing changes. It is your Worker.
Rate limits Whatever plan you bought Meta's actual limits
Reading the code No 4,400 lines. One dependency. No build step.

It uses Meta's official Graph API through Instagram Login. No scraping, no browser automation, and it never sees your Instagram password.


How it works

flowchart LR
    A["πŸ’¬ Someone comments<br/>&quot;guide&quot;"] --> B{{"Meta webhook<br/><i>HMAC signed</i>"}}
    B --> C["⚑ Your Cloudflare Worker"]
    C --> D{"Is it you?"}
    D -->|yes| X["🚫 ignored"]
    D -->|no| E{"Already handled?"}
    E -->|yes| X
    E -->|no| F{"Matches a<br/>keyword rule?"}
    F -->|no| Y["πŸ“ logged as skipped"]
    F -->|yes| G["πŸ“¨ One private DM"]
    G --> H["πŸ’­ Optional public reply"]

    P["⏱ Every 5 minutes"] -.->|"catches what the<br/>webhook missed"| C
    N["πŸŒ™ Nightly 03:00 UTC"] -.->|"refreshes the<br/>60-day token"| C

    style A fill:#FD1D1D,stroke:#833AB4,color:#fff
    style C fill:#F38020,stroke:#833AB4,color:#fff
    style G fill:#22aa66,stroke:#0a5,color:#fff
    style X fill:#eee,stroke:#999,color:#333
    style Y fill:#eee,stroke:#999,color:#333
Loading

Two independent delivery paths. The webhook is the fast one β€” a DM lands in about two seconds. The five-minute poll is the safety net, because Instagram quietly drops webhooks for collapsed and low-signal comments. A comment that the webhook missed still gets its DM, just a few minutes later.

Everything lives in one Worker and one SQLite database:

Runtime Cloudflare Workers β€” no servers, no containers, no cold-start cost
Database Cloudflare D1 (SQLite) β€” five tables
Framework Hono, server-rendered HTML
Dependencies One. Web Crypto does the hashing, HMAC, and AES.
Client-side JS None at all
Build step None

Quick start

You need Node.js 20+, a free Cloudflare account, and an Instagram professional account (Creator or Business β€” switch in the app under Settings β†’ Account type and tools).

git clone https://github.com/CharanMN7/ig-comment-dm.git
cd ig-comment-dm
npm install
npx wrangler login

npm run setup

npm run setup creates the database, generates every secret at the right size, deploys, and finishes by printing the exact strings to paste into Meta's dashboard:

[1/6] Checking your Cloudflare login
[2/6] Creating the database and deploying
[3/6] Creating the database tables
[4/6] Your three values from the Meta dashboard
[5/6] Generating the rest
[6/6] Deploying again so the secrets take effect

Done. Your copy is live.

It is safe to re-run, and it will not rotate secrets you already have.

Important

Before that, you need a Meta app β€” about 15 minutes of clicking, and the part that trips everyone up. docs/setup.md walks through every screen, including the four traps that cost people an evening each.

Stuck? Run npm run doctor. It checks your live deployment and tells you what is missing in plain words.

Why clone instead of a template repo?

Because a fresh clone needs zero file edits to deploy β€” Wrangler provisions the D1 database from the config, so there is no placeholder to fill in. Nothing about the code differs between deployments; the only per-user values are Cloudflare secrets, which never touch the repository.

A GitHub template would sever the upstream link. Meta renames dashboard screens, retires OAuth hosts, and changes signing behaviour often enough that git pull needs to keep working:

git remote add upstream https://github.com/CharanMN7/ig-comment-dm.git
git pull upstream master
npx wrangler deploy

Your secrets live in Cloudflare, so updating never touches them.


User guide

Connect an account

Open your admin URL (printed by npm run setup β€” bookmark it) and create a password on the first visit. Then Accounts β†’ Connect a new account.

You can connect several Instagram accounts to one deployment. Each one needs to be an Instagram Tester on your Meta app.

Write a rule

Rules β†’ New rule.

Field What to put
Name For you only. Free guide.
Keywords One per line. At least 3 characters β€” AI would fire on "again" and "email".
The DM Under 1,000 characters. Put everything they need here.
Public reply Optional. Shows under the comment.
Which posts All posts and reels, or pick one from the dropdown.

Matching ignores case, emoji, and punctuation, and matches whole words. A rule scoped to a specific post beats a rule that applies to everything.

Tip

Put everything in that one message. Instagram allows exactly one private reply per comment, ever. You do not get a follow-up unless they reply to you first.

Test it without messaging anyone

Test β†’ paste a sample comment. It shows which rule would fire. Nothing is sent.

Then comment from a different Instagram account β€” a friend's phone works. Your own comments on your own posts are ignored deliberately.

Read the Home page

Panel What it tells you
Did Instagram reach us? Whether Meta is POSTing at all. Empty means the problem is on Meta's side, not yours. Wrong secret means FACEBOOK_APP_SECRET is missing.
Last 20 sends Every DM, skip, and failure, with the reason.
Red banners An account needs reconnecting, the nightly job has stalled, or a secret is misconfigured.

Things that will surprise you

Instagram's rules, not ours. Each of these is enforced by Meta and cost someone an evening to discover.

πŸ“¨ One private message per comment, ever. A second attempt is blocked here, and Meta would reject it anyway.
πŸ™ˆ Your own comments are ignored. Meta notifies you about them; acting would DM yourself and burn the one reply.
πŸ“… Comments older than 7 days cannot receive a private reply. They are logged as skipped.
πŸ”‘ Tokens expire after 60 days. A nightly job refreshes them. Miss it and the account needs a 20-second reconnect.
🚧 A Development-mode app delivers nothing. Meta only sends the dashboard Test button until you click Publish. This is the number one reason a correct setup does nothing.
🀐 Hidden Words eats comments before we see them. If Instagram's filter hides a comment, it never reaches the API at all. Turn the filter off while testing.
⏳ Missed comments arrive late, not never. The five-minute poll catches them.

Roadmap

Shipped

Core pipeline
  • Comment β†’ one official Instagram private reply, end to end
  • Optional public reply under the comment
  • Keyword rules with case, emoji, and punctuation normalisation, matched on word boundaries
  • Post-scoped rules take priority over account-wide rules
  • Reel and post picker, so nobody has to hunt for a Graph media id
  • Self-comment guard β€” never DMs the account owner
  • Exactly-once delivery, claimed atomically in the database before sending
  • 7-day comment age guard, matching Meta's private-reply window
  • Dry-run rule tester that sends nothing to real people
Reliability
  • HMAC-verified webhooks, accepting either the Instagram or the Facebook app secret
  • Five-minute reconciliation poll for comments the webhook never delivered
  • Nightly token refresh with a 10-day lookahead and a reconnect warning
  • Automatic subscribed_apps registration after Connect
  • Retry with jittered backoff on Meta 429s and 5xxs
  • Large Instagram ids preserved exactly, instead of being mangled by JSON number parsing
  • Inbound webhook log, including rejected signatures, so silence is diagnosable
Security and operations
  • Instagram tokens encrypted at rest with AES-256-GCM
  • Two-factor admin: a 128-bit secret path plus a password
  • Signed, HttpOnly, SameSite=Strict sessions with CSRF tokens on every form
  • Referrer-Policy: no-referrer so the secret admin URL never leaks to a third party
  • Login rate limiting with a doubling lockout
  • Constant-time comparison of the admin path secret
  • Startup validation of all eight secrets, surfaced in the admin panel
  • npm run setup β€” clone to deployed in one command
  • npm run doctor β€” diagnoses a live deployment
  • Multi-account support on a single deployment
  • Hosted privacy, terms, and data-deletion pages for Meta review

Planned

Everything below is an open issue. Comment on one to claim it β€” good first issue items are self-contained and have the approach sketched out.

🎯 Automation
Issue Feature Why it matters
#23 Tracked links with click analytics Know whether the DM actually worked, not just that it sent
#24 Button templates in DMs A tappable CTA converts far better than a bare URL
#25 Opening DM + reveal on tap Works around Meta's one-reply-per-comment limit legitimately
#26 Follow gate Deliver the link only after they follow
#27 Follow-up DM after a delay A second touch inside the 24-hour window
#29 Reply to DMs and story replies The same keyword rules, triggered by inbound messages
#30 {username} and {link} placeholders Personalised copy without a rule per person
#31 Public reply variations Rotate replies so a comment section does not read like a bot
#32 Match any comment Fire on every comment on a post, no keyword needed
#33 Bind a rule to the next reel you post Set the automation up before the content exists
#34 Ad-comment to organic-post mapping Boosted posts report a different media id and silently miss
#35 Per-account rate limiting Stay under Meta's 750 private replies per hour
#36 Send every matching rule's public reply Today the second matching rule is silently dropped
#22 Negative keywords Skip "not interested", "how much is the guide"
#37 Bulk rule import from CSV Set up thirty posts without thirty forms
#38 Rule templates Working starting points per niche
πŸ”€ Matching
Issue Feature Why it matters
#19 Non-Latin script matching Word-boundary matching silently drops Cyrillic, Arabic, and CJK today
#20 Latin diacritic folding PREÇO should match a preco keyword
#21 Whole-word vs. partial toggle Hashtag campaigns need substring matching
πŸ“Š Analytics
Issue Feature Why it matters
#39 Dashboard totals Sent today, this week, this month, all time
#40 Sends-over-time chart Inline SVG, no JavaScript
#41 Per-rule performance Which keyword is actually earning its place
#42 Top matched keywords What your audience really types
#52 Follower history Instagram only keeps 30 days; daily snapshots keep more
#53 Post insights Views, reach, saves, and shares next to the sends
#43 Shareable report page A read-only link for a client, no login
#44 Filterable, paginated send log Twenty rows stops being enough quickly
πŸ”Œ Instagram coverage
Issue Feature Why it matters
#28 messages webhook field Prerequisite for DM triggers and the inbox
#54 DM inbox Read replies without leaving the panel
#48 Typed Meta errors "Token expired" beats "Graph API error 190"
πŸ›  Operations
Issue Feature Why it matters
#45 Tracked migration runner Adding a migration should not mean editing two npm scripts
#46 Health check endpoint Uptime monitoring without a login
#47 Operational event log Cron failures are invisible until something breaks
#49 Export rules and logs Your data, portable
#50 Dark mode The panel is white at 1am
#51 Installable on a phone Approve and edit rules from where you actually post

Tip

New here? These four are self-contained, need no Meta app to test, and have the approach written out in the issue: #19 non-Latin keyword matching Β· #30 {username} placeholders Β· #50 dark mode Β· #48 human-readable Meta errors


Documentation

docs/setup.md Every Meta dashboard screen, and the traps in each
docs/troubleshooting.md Symptom-first. Start here when nothing happens.
docs/architecture.md Routes, pipeline, cron, crypto
CONTRIBUTING.md Setup, house style, what belongs here
SECURITY.md Threat model, secret inventory, rotation, private reporting

Contributing

Issues and pull requests are welcome. good first issue items are self-contained and describe the approach.

npm install
npm test          # 30 unit tests, no network, no database
npm run typecheck
npm run dev       # http://localhost:8787

Read CONTRIBUTING.md first β€” particularly the constraint that keeps this project usable: one runtime dependency, no build step, no client-side JavaScript.

Found a security problem? Do not open an issue. See SECURITY.md.


Star history

Star history chart



MIT licensed Β· Built on Cloudflare Workers and Hono

Not affiliated with, endorsed by, or sponsored by Meta or Instagram.
Instagram is a trademark of Meta Platforms, Inc.

About

Instagram comment-to-DM automation you actually own. One Cloudflare Worker, one D1 database, $0/month. Self-hosted ManyChat alternative.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages