Self-hosted Instagram comment-to-DM automation on Cloudflare Workers using the official Meta Instagram API.
This project is a single-account template for creators and small operators who want to own their infrastructure instead of giving a third-party SaaS direct access to Instagram audience workflows. "Comment a keyword, get the link in your DM" — without renting it.
- Watches configured Instagram media IDs for configured comment keywords, with typo-tolerant fuzzy matching (Damerau-Levenshtein, word-order and stop-word aware).
- Records Meta webhooks in Cloudflare D1 with idempotency, plus a cron poller that catches missed webhooks.
- Queues an opening private reply with a postback button; the flow engine also supports chained DM button steps and auto-advancing to the final delivery (multi-step saves stay locked off in this template for App Review-grade behavior).
- Rotates message variants deterministically per user (opening, public reply, and each DM step), backed by a reusable searchable template library.
- Sends an optional public comment reply after the opening delivery is marked sent, and an optional public rescue reply when the DM cannot be delivered.
- Supports an optional follow gate: the final prompt waits until the user follows the account, with a retry button and
READYtext fallback. - Sends the final prompt or link only after user interaction by default.
- Ships a browser admin console at
/admin-uiwith a guided campaign builder, live Instagram-style preview, readiness checklist, and operational dashboard. - Refreshes long-lived Instagram tokens on a schedule and stores refreshed tokens AES-GCM-encrypted in D1.
- Keeps a global
AUTOMATION_ENABLEDkill switch and a local outbound send rate limiter. - Does not ship an OAuth callback route; the single-account setup uses a Meta-generated Instagram token.
flowchart LR
A["Instagram comment"] --> B["Meta webhook"]
B --> C["Cloudflare Worker"]
C --> D["D1 event and state"]
C --> E["Delivery queue"]
E --> F["Official Meta API send"]
C --> G["Admin UI and API"]
This repository intentionally uses only the official Meta API. It does not use Instagram passwords, session cookies, scraping, browser automation, Selenium, mobile session replay, or unofficial private APIs.
The default flow is narrow:
- A user comments a configured keyword on a configured media ID.
- A signed Meta webhook or fallback poller records the event.
- The Worker queues an opening private reply.
- Optional public comment reply is queued only after the opening send succeeds.
- The final prompt normally waits for a button postback or matching text.
AUTO_FINAL_AFTER_OPENING=true exists for fallback-heavy environments, but it should stay off for safer App Review behavior.
Prerequisites:
- Node.js 22 or newer.
- npm 11.8.0 or compatible.
- A Cloudflare account with Wrangler authenticated before remote deploy.
- A Meta developer app with Instagram API access for a Business or Creator test account.
npm install
cp .dev.vars.example .dev.vars
cp wrangler.example.toml wrangler.toml
npm run db:migrate:local
npm run devThen check:
curl http://localhost:8787/healthAdmin console:
http://localhost:8787/admin-ui
npx wrangler d1 create ig-autodm-worker
npx wrangler queues create ig-autodm-deliveries
npx wrangler queues create ig-autodm-deliveries-dlqCopy the generated D1 database ID into your local wrangler.toml, then configure Worker secrets:
npx wrangler secret put META_APP_SECRET
npx wrangler secret put META_VERIFY_TOKEN
npx wrangler secret put INSTAGRAM_ACCESS_TOKEN
npx wrangler secret put INSTAGRAM_ACCOUNT_ID
npx wrangler secret put ADMIN_TOKEN
npx wrangler secret put ADMIN_LOGIN_USERNAME
npx wrangler secret put ADMIN_LOGIN_PASSWORD
npx wrangler secret put AUTOMATION_ENABLED
npx wrangler secret put TOKEN_ENCRYPTION_KEYOptional:
npx wrangler secret put INSTAGRAM_MESSAGING_ACCOUNT_IDS
npx wrangler secret put INSTAGRAM_APP_SECRET
npx wrangler secret put TURNSTILE_SECRET_KEY
npx wrangler secret put TURNSTILE_SITE_KEY
npx wrangler secret put META_SENDS_PER_MINUTE
npx wrangler secret put AUTO_FINAL_AFTER_OPENINGGet INSTAGRAM_ACCESS_TOKEN from the Meta App Dashboard for the connected Instagram Business or Creator test account. To find INSTAGRAM_ACCOUNT_ID, call /me with that token and use the returned user_id:
read -r -s IG_ACCESS_TOKEN
curl -H "Authorization: Bearer ${IG_ACCESS_TOKEN}" \
"https://graph.instagram.com/v25.0/me?fields=user_id,username"
unset IG_ACCESS_TOKENINSTAGRAM_MESSAGING_ACCOUNT_IDS is optional. Leave it unset unless real messaging webhooks show an entry or recipient ID that differs from INSTAGRAM_ACCOUNT_ID; if needed, store a comma-separated placeholder-safe list of allowed IDs.
Run before deploying or opening a PR:
npm run typecheck
npm run infra:validate
npm run test:coverage
npm audit --json
npm audit signatures
npm run scan:oss
git diff --checknpm run db:migrate:remote
npm run deployAfter deploy, your Worker URL will look like:
https://<worker-name>.<cloudflare-account>.workers.dev
Use this shape in the Meta dashboard:
https://<worker-name>.<cloudflare-account>.workers.dev/webhooks/meta
Keep AUTOMATION_ENABLED=false for the first deploy. After health, webhook verification, admin login, and one disabled/draft campaign are verified, set it to true and enable only the test campaign for the first end-to-end run.
SaaS comment-to-DM tools sit between your Instagram account and your audience: they hold your access token, your contact data, and your monthly bill. This template runs the same workflow on your own Cloudflare account — typically within the free tier — with HMAC-verified webhooks, encrypted token storage, rate-limited sends, and an auditable admin surface you fully control.
If this replaces a subscription for you, a star helps other creators find it.
- Product Requirements
- Requirements
- Architecture
- Security and Compliance
- Meta App Review Playbook
- Cost and Operations
- Roadmap
- API Reference
- Feature Matrix
- Runbook
- Contributing
- Security Policy
- Code of Conduct
MIT.
