Someone comments LINK on your reel. OpenReply queues a DM with your link, through Meta’s official private-reply API, and optionally posts a public reply under the comment. That is the entire product, and it is the one feature every social tool sells as a monthly subscription.
OpenReply is MIT-licensed and self-hosted. There is no hosted plan to upgrade to — the public demo at openreply.diwen.dev is a dashboard demo and will never send a DM for you. You deploy your own copy, run your own worker, and connect your own Instagram account.
I cloned it and checked the numbers, the docs, and the free tier it recommends. The engineering is better than the average “open-source alternative” launch. The documentation is more honest than most commercial vendors’. And the most interesting thing about the project is a boundary that is documented in a subordinate clause and determines whether the whole thing is free or not.
What OpenReply actually is
Two Node processes and two datastores, and the split is not decorative:
- Web app and API — Next.js 16 with React 19, App Router. Serves the dashboard, the OAuth callback, and the incoming webhook. Deployed on Vercel.
- Worker — a long-running Node process (
npm run worker, run throughtsx). Consumes the send queue, sends the DMs, runs the polling reconciler for missed comments, and performs the follow-gateis_user_follow_businesschecks.
The worker’s existence follows from one sentence in the docs: “It cannot run on Vercel, because serverless functions are short-lived and a queue consumer has to stay up.” A DM send has to survive Meta’s rate limits and retries, so it needs a process that is always on. Vercel only runs the front half.
The rest is PostgreSQL through Prisma 7, Redis through BullMQ 5 for the send queue and the per-account rate limiter, Auth.js with email magic links through Resend, Tailwind for the interface, and the official Instagram API with Instagram Login. Fourteen runtime dependencies in package.json, which is lean for what this does.
The repository at main:
- 247 files, 191 commits, TypeScript 97.4%
- 44 test files under
__tests__/ - 18 Prisma models and 7 enums in a 421-line
schema.prisma - CI runs typecheck, lint,
vitest runand a production build on every push and pull request
The feature list is broader than the one-line pitch: keyword matching with whole-word or partial modes, tracked links with per-campaign CTR, up to two tappable DM buttons each with its own click stats, a follow gate that re-prompts until the follow is confirmed and fails open when Meta does not return follow status, per-account rate limiting that queues overflow instead of dropping it, workspaces with owner/admin/member roles and invite links, campaign templates, an inbox for reading and replying inside Meta’s 24-hour window, and DM logs that record every send, skip and failure with a reason.
There is also an interface language selector with English, Traditional Chinese and Brazilian Portuguese. The pt-BR support arrived as a community pull request in the last day of the working tree I cloned, which is a sign the project is still alive rather than archived-and-forgotten.
The free path is real, and it ends at your own account
Here is the part the headline does not carry. Instagram comment-to-DM is a privileged feature that Meta controls, and the control is not a rate limit. It is who is allowed to use the permission at all.
OpenReply documents two ways to connect Instagram. The first is your own Meta app. The second is Zernio, a paid third-party connection provider, which is also the project’s sponsor.
If you take the first path for your own accounts, it works and it costs nothing. Add your Instagram username as an app tester, accept the invite on the Instagram side, and Standard Access covers you. No App Review. The docs say this plainly: “Everything above is enough to run OpenReply for your own accounts, or a handful of accounts you add as testers. No App Review needed.”
If you want someone else’s account — a client’s, a customer’s, anyone who is not a tester on your app — the path changes completely. META_APP_REVIEW.md lists what is required: a screencast of the whole flow recorded in one take on real accounts, a written justification for each of the three permissions, and then this:
“Meta usually requires business verification before granting Advanced Access. It asks for a document proving a legal entity: a business registration or license, articles of incorporation, a business tax document, or a business bank statement. If you do not have a registered business, you cannot complete this step, and the practical path is to run OpenReply for your own accounts instead, which never needs review.”
Read that again as an operator rather than as a reader. The software is free, the API is free, the hosting can be free — and the one thing standing between you and serving a paying client is a document issued by a government. A freelancer, a solo operator, someone testing an agency idea before incorporating: all of them are outside the free path, not by policy choice of the project, but by the structure of the platform underneath it.
The docs attach a second warning that matters for planning: “Meta scrutinizes automated-DM apps and often rejects the first submission, so budget for a resubmit.”
The sponsor’s business model is the wall you hit
Zernio is described in the README as “an optional paid Instagram connection provider that lets you avoid creating and reviewing your own Meta app.” It is also the project’s sponsor, and every documentation link to it carries utm_source=openreply&utm_medium=sponsorship&utm_campaign=openreply-integration.
Zernio itself is a much larger company than the sponsorship suggests. It bills itself as “marketing infrastructure for agents” — one API across social platforms, blogs, ads, phone numbers, SMS, WhatsApp and iMessage, with an MCP server and integrations advertised for Claude Code, Cursor, Codex and similar tools. Its front page claims “200,000+ builders” and, on the day I fetched it, “32,613 accounts connected this week.”
Its pricing is per connected account, no plans and no seats: 1–2 accounts free, 3–10 at $6 per account per month, 11–100 at $3, 101+ at $1, with the advertised average landing at $4.80 per account. The first 10,000 sent messages each month are included.
And its marketing copy names the wall precisely:
“Skip months of platform approvals and go live today.” “We’ve done the platform reviews, so you don’t have to.” “Platform changes, token rotations, and rate limits are ours to absorb.”
None of this is concealed, and the project does not pretend otherwise. docs/setup.md labels Zernio “recommended for simpler connection setup” and states in the same table row that it is a paid provider and that it sponsors OpenReply. The AI-assistant setup prompt shipped with the repository is explicit about it too, instructing the assistant to “clearly disclose that it is an optional PAID service and OpenReply sponsor” before recommending it.
That is more disclosure than most sponsored open-source projects bother with, and it deserves saying. But disclosure does not change the shape of the thing: the free tier of this free software stops at the exact point where the sponsor’s paid product starts. Whether you read that as a sustainable funding model for a solo maintainer or as a funnel with an MIT license on the front, the practical consequence for you is identical. You either have a registered entity, or you are paying per account.
I would rather a project be funded this way than be abandoned, and the alternative — no sponsor, no maintained compatibility with whatever Meta changes next quarter — is not obviously better. It is simply worth seeing the boundary before you plan a business on top of it.
What I measured in the repository
The growth numbers are unusual in a way that is worth writing down, because they do not match the shape of a typical viral launch.
- 2,544 stars, but 12 watchers. Watchers are the people who chose to receive notifications — the strongest available signal of intent. Twelve against 2,544 stars is 0.47%. On repositories that reach this kind of attention, watchers usually run an order of magnitude higher.
- 1,037 forks against 2,544 stars. A fork-to-star ratio of 40.8%. For a self-hosted application, forking is the deployment path, so an elevated ratio is expected — but 40.8% is far above the usual band, and it says most of those stars are not from people reading the code.
- Zero releases and zero tags. Not “no recent release” — no releases at all.
package.jsonsays0.1.0, and there is no tag pointing at anything. There is no version to pin, no changelog to diff, no artifact to download. Everyone who deploys this is cloningmainat whatever commit they happened to get, which also means the “should I upgrade” question has no clean answer. - 28 contributors, and 26 of them have eight commits or fewer. The maintainer, Diwen Huang, has 108 of the 191 sampled commits. The original author of the upstream project it was forked from has 28. The rest is a long tail of one- to eight-commit contributions, which is normal for a repository with a
good_first_issuetemplate and a contribution guide — and also means the bus factor is one for anything structural. - No discussion on Hacker News. I searched. OpenReply does not appear. The category it belongs to does: I found at least two other Show HN posts from the same period advertising open-source, self-hostable ManyChat alternatives, both of which scored in the low single digits. It is a crowded lane, and the star count here is not coming from the usual launch channels.
- The commit timeline has a spike and a taper. The repository was created in July 2026, but commits reach back to April because the fork preserved upstream history. July carries 100 commits of 191; August 24, September 35, October 4 at the time of the clone. The pattern — one large push when the project was re-established as an open-source product, then steady maintenance — fits a single maintainer building in their own time.
The fork history also explains a file that otherwise looks strange: the migrations directory contains a remove_billing migration dated May 2026, and the first five migrations build a “B2B SaaS foundation.” This was not written as an open-source project and then licensed MIT. It was a commercial SaaS that was converted.
The free tier’s ceiling, in numbers
docs/stack.md publishes the exact zero-cost stack the maintainer runs, which is a welcome level of specificity, and it makes the ceilings calculable rather than vague:
| Piece | Service | Free allowance |
|---|---|---|
| Web app | Vercel (Hobby) | Free |
| PostgreSQL | Neon | ~0.5 GB |
| Redis | Redis Cloud (Essentials) | 30 MB, TCP required |
| Worker (24/7) | Oracle Cloud “Always Free” VM (VM.Standard.E2.1.Micro, Ubuntu 22.04, pm2) | Free forever |
| Login email | Resend | 3,000 emails/month |
| Instagram API | Meta app with Instagram Login | Free |
The docs already flag one constraint that surprises people: “Vercel’s free plan allows each cron to run at most once per day. The repo’s crons are set to daily for that reason.” The token-refresh cron is therefore a daily job, which is fine, but it means anything you would want on a finer schedule cannot live there.
The two numbers nobody has computed are the database and the queue, so I did, and the answers are less comfortable than the rest of the stack.
PostgreSQL at 0.5 GB. This application logs aggressively by design: DmLog records every send, skip and failure with a reason, WebhookEvent stores inbound deliveries, OperationalEvent stores worker crashes and reconciler sweeps, and tracked links add click events on top. A single DM log row with its stored payload is roughly 1–3 KB. At 2 KB per row, 0.5 GB is on the order of 250,000 rows before you are at the ceiling — and that ceiling counts everything, not just the log table, and it does not account for Postgres’s own overhead, indexes, or table bloat. An account sending 500 DMs a day reaches it in about a year and a half. An account sending 5,000 a day reaches it in about seven weeks.
Redis at 30 MB. BullMQ holds job payloads plus the state it keeps for completed and failed jobs. A queued job carrying campaign and recipient context is realistically 2–5 KB. At 3 KB per job, 30 MB is on the order of 10,000 jobs in flight. That sounds generous until you compare it with the platform limit the application is built to respect: 750 private replies per hour, per account. A rate-limit backlog that reaches even a few hours’ worth of traffic starts pressing on the free Redis, and the free Redis is the component with the least headroom in the whole stack.
Neither limit is a design flaw. They are the natural consequence of choosing the free tier of everything, which is a reasonable choice for the audience the docs target. But “free forever” and “free at the volume where this becomes a business” are different claims, and only the first one is on the table.
Three failures that cost an afternoon each
The documentation devotes space to three failure modes that share a property: the error message points somewhere other than the cause. I am listing them because they are the best argument that this project’s docs were written from real operation rather than from a template.
1. Publishing your app does not widen who can connect. A published Meta app still holds Standard Access to instagram_business_basic, instagram_business_manage_comments and instagram_business_manage_messages. Publishing makes the app live; it does not change which accounts the permissions cover. So your first account connects perfectly and your second account — a client’s — fails. The symptom, quoted from the guide: the consent screen appears, the login succeeds, the code exchange returns a valid IGAA… token with every requested permission, and then every call against graph.instagram.com is refused with:
Unsupported request - method type: get [code=100, type=IGApiException]
Nothing in that message suggests a missing role, and the token is not the problem.
2. A previous tool can still own the conversation. If the Instagram account was ever connected to ManyChat or another comment-to-DM tool — even if the subscription was cancelled — that tool can remain the conversation owner on Meta’s side. The result is a partial failure that looks like a code bug: comments work, the public reply posts, the first DM arrives, and then every button tap inside the DM fails silently with The action is invalid since it's not the thread owner. [code=100 sub=2534037]. The fix is not in OpenReply at all; it is in Meta Business Suite under Settings → Integrations → Conversation routing → Partner apps, where you remove the old tool and grant your app both “Access all conversations” and “Take control of conversations.” Instagram deliberately lets any connected app send that first private reply, which is exactly why the failure only shows up on the second interaction.
3. The encryption key is a single point of failure with no recovery path. ENCRYPTION_KEY must be byte-identical on the web app and the worker, because the web app writes the encrypted Instagram token and the worker decrypts it to send. A mismatch means every send fails to decrypt. Losing it later means the same thing permanently, for every connected account, with no migration path: the docs say “Losing or changing it means every connected account has to reconnect.” On a distributed free stack — Vercel plus a separate worker host plus a managed Postgres — that key is the one piece of state that has to be right in three places and has no backup besides the one you make yourself.
There is a fourth, structural one worth naming. The worker must be always-on and the free options are not equivalent. Oracle’s always-free micro instance is 1 GB of RAM on a shared tenancy with a well-documented history of unannounced reclaiming, kept alive by pm2. It will run this application. It is also the component most likely to disappear without warning, and when it does the failure mode is “webhooks arrive, nothing sends” — visible in /api/health as worker.healthy: false, and invisible to the person who commented and got no reply.
Who this is actually for
It is genuinely good for a solo creator or a single brand running its own account. This is the case the free path was designed around. You connect one or two professional accounts, add your own username as an app tester, skip App Review entirely, and run the whole thing on the documented free stack. The workflow it automates is one that ManyChat and its competitors charge monthly for, and you get a self-hosted, inspectable implementation of it for the cost of your time. The follow gate, the tracked link buttons and the DM logs are real features, not checkboxes.
It is genuinely good for a technical agency that already has a registered legal entity. Business verification is the hard gate, and if you clear it, App Review unlocks Advanced Access and the account count stops being a billing line. At that point the sensible move is to stop using the distributed free stack and self-host the worker, Postgres and Redis on one VPS, because the 30 MB Redis and 0.5 GB Neon limits were never sized for client volume.
It is a bad trade for a freelancer or a solo operator without a company. Not because the software is bad, but because the free path is closed to you by a requirement you cannot satisfy, and the paid path is per-account pricing that scales with your client count. At three to ten accounts the sponsor costs $6 per account per month; add a hosting upgrade for the worker and a database that fits real traffic, and you are close to the subscription you were trying to escape — while also owning the operations. The words to search for are the ones docs/setup.md uses: “If you do not have a registered business, most self-hosters skip this entirely by running their own instance for their own account.” That sentence is doing a lot of load-bearing work.
It is a bad trade for a non-technical marketer. The three failure modes above are not edge cases; they are the ordinary first-week experience of connecting Instagram through Meta. Diagnosing the thread-owner failure requires reading a code=100 sub=2534037 error and knowing to look in Business Suite. Migrating from another tool has a documented, non-obvious ordering requirement. If your time is worth more than a subscription, the subscription is the cheaper product.
FAQ
Is OpenReply really free? The software is MIT-licensed and free, and the Instagram API itself is free. Hosting is free if you use the documented free stack. What is not free is serving other people’s Instagram accounts: that requires Meta App Review with business verification, which requires a registered legal entity. If you have one, the marginal cost stays near zero. If you do not, your options are your own accounts only, or a paid connection provider.
Can I use it for my clients right now? Only if you pass Meta’s business verification, or if you pay a connection provider like Zernio. The free route covers accounts that have a role as admin, developer or tester on your app, and that list effectively means you and the people you personally invite.
Do I need a VPS? Yes, unless you pay for an always-on plan elsewhere. The worker is a long-running process and the docs state it cannot run on Vercel because serverless functions are short-lived. Railway, Render, Fly or any always-on box works; the reference free deployment uses an Oracle always-free micro VM.
Why is the DM button tap failing when the first DM worked? Almost certainly thread ownership. Instagram lets any connected app send the one private reply triggered by a comment, but every message after that must come from the app that owns the conversation. If the account was ever connected to another comment-to-DM tool, remove it and take control in Meta Business Suite → Settings → Integrations → Conversation routing → Partner apps.
Does it do anything with TikTok or other platforms?
Not in main at the commit I cloned. There is an open pull request proposing TikTok comment auto-replies through the TikTok API for Business, and another proposing a read-only workspace API with MCP support. Neither is merged.
What happens when Meta changes the API?
You patch your fork. There are no releases and no tags, so there is no version to pin and no upgrade story beyond pulling main. One maintainer has 108 of 191 sampled commits, and Meta revises Graph API versions on a regular cadence, so maintenance capacity is the real long-term risk rather than any specific bug.
Is it safe to connect my Instagram account?
The design is compliant rather than clever: official Instagram API only, no scraping, no browser automation, no password handling, tokens encrypted at rest with AES-256-GCM. The compliance risks are operational — keep ENCRYPTION_KEY backed up somewhere you will find it, and keep the ALLOWED_EMAILS allowlist closed, because an unset allowlist means anyone reaching your URL can request a magic link and get their own workspace.
Conclusion
OpenReply is the rare “open-source alternative” that deserves the label. The engineering is careful, the documentation is written from practice, and the published free stack is specific enough to be audited rather than gestured at. If you run your own Instagram account and want comment-to-DM without a subscription, this is a credible way to get it, and the amount of operational knowledge encoded in docs/setup.md is worth reading even if you choose a different tool.
What I would want a reader to take away is narrower than “it’s free.” The feature it automates sits behind a Meta permission that the platform does not hand out on technical merit. For your own account, that permission is effectively yours. For a client’s account, it requires a legal entity, a screencast, written justifications and a resubmission budget — and the project’s own documentation, written by a maintainer who is clearly trying to be straight with people, tells you to stay on your own account instead. Everything else follows from that line: why the sponsor’s pitch is “we’ve done the platform reviews”, why the free tier stops where it does, and why this is a good tool for one audience and an expensive detour for another.
Check which side of the boundary you are on before you deploy. It takes one question: are the Instagram accounts you intend to connect your own, or someone else’s.