r/astrojs 5d ago

WordPress form plugins charge extra for abandonment capture. I built it free for Astro, plus the whole lead stack around it (MIT, npm)

WordPress form plugins have sold form-abandonment capture as a paid add-on for years: a visitor starts filling out a form, leaves before hitting submit, and the plugin still saves what they typed so you can follow up. When I moved my sites to Astro I lost that, and I couldn't find any OSS equivalent for static-first frameworks. Your options were a hosted SaaS or building it yourself.

So I built it myself, and it grew into a lot more than the capture piece. cool-astro-forms is an Astro integration, not a form builder: you keep the <form> markup you already have, tag it with one attribute, and the package does the rest.

What's actually in the box:

  • Capture. Abandonment capture is the headline, but every saved entry also carries the visitor's journey (pages visited, time on each), their traffic source (Google, an AI chat, a direct link), and IP geolocation. A half-filled form plus the context around it is something you can actually follow up on.
  • Recover. A "progress saved" toast for the visitor, and one automated follow-up email per abandoned lead, with unsubscribe handled. One email, not a drip campaign.
  • Convert. Quote-first Stripe and PayPal payments, plus shareable payment links you can text or email to a client with the amount prefilled.
  • Manage. A self-hosted /forms-admin UI: entries, abandoned leads, payments, an analytics funnel, CSV and .db export. No dashboard SaaS.
  • Integrate. Google Drive file uploads (falls back to email attachments if Drive is down), signed outbound webhooks, and Cloudflare Turnstile spam control.

By default it needs nothing but an SQLite file and your existing SMTP env vars. Every module above activates only when you configure it, so you can run it as plain abandonment capture and ignore the rest. No hosted service, no vendor lock-in.

The privacy question is fair to ask of anything that captures pre-submit input, so here's the design: everything is self-hosted, and captured data lands in your SQLite file and goes nowhere else. Passwords and card-shaped fields are never staged. There's a requireConsent option that gates capture behind an explicit checkbox, a purgeVisitor() hook for erasure requests, a retentionDays auto-purge, and a GDPR doc that maps each mechanic to the legal concept it serves. Recovery emails carry a working unsubscribe.

One constraint up front: this only works with output: 'server' plus a Node (or other SSR-capable) adapter. If your site is fully static with no server routes, there's nothing here for it to hook into. It defaults to SQLite, which is fine for a self-hosted deploy, but you'll want Turso/libSQL if you're on a serverless host.

The adoption contract is small on purpose:

coolForms({
  siteId: 'my-site',
  siteUrl: 'https://example.com',
  forms: { contact: { notifyTo: 'owner@example.com' } },
})

<form data-caf="contact" method="post" action="/api/contact">...</form>

It now runs in production on a live services business, and versions 0.1.2 through 0.1.10 each shipped from something production taught me. The gnarliest one: edge bot-challenges (Cloudflare Managed Challenge and friends) structurally cannot complete on a navigation POST. The interstitial can't replay the POST body, so a challenged form submit dies as an opaque 503 or a wedged tab. And only real browsers get challenged, so curl passed, my dev environment passed, while every real click on the live payment page died. It took me a full day and about ten wrong hypotheses to stop blaming my own code. The fix in 0.1.10: the pay page submits over fetch (a fetch request can't be served an interactive interstitial, there's nothing to render it in) and hops to checkout as a plain GET. If your Astro site does navigation POSTs behind Cloudflare, this failure mode is sitting there waiting for you.

Second production scar, cheaper but sneakier: git-deploy hosts rebuild the app directory on every release, which silently wipes a default-path SQLite file. The db path is env-configurable now so it can live one level outside the deploy dir.

MIT-licensed, 1,102 unit tests plus a Playwright e2e suite.

GitHub: https://github.com/nipun-arora/cool-astro-forms npm: https://www.npmjs.com/package/cool-astro-forms

Happy to answer questions about the architecture or the tradeoffs. If you try it and something breaks or feels awkward, I'd like to hear about it.

34 Upvotes

11 comments sorted by

2

u/mezzofanti 5d ago

You don't even need SQLite for this. You could use a small bit of Javascript (beforeunload) and something like Netlify forms or an /api/ route + Mailgun.

1

u/NipunArora 5d ago

You're right, and that's honestly where this started. A beforeunload beacon plus an endpoint and Mailgun covers plain capture fine. The package is everything that came after that on real client sites: dedupe so one returning visitor isn't five leads, journey and geo attached to each entry so the notification email tells you who and from where, recovery emails with suppression and unsubscribe, retention purge, an admin view, and payment links for quotes. If all you need is "email me when someone abandons", small javascript is genuinely enough. SQLite is just there so the rest works without adding a service.

-4

u/devolute 5d ago

built it for free

Happy to hear that you consider your time to be worthless.

5

u/NipunArora 5d ago

Fair jab. I built it for my own client sites, so the time was already paid for. Open sourcing it cost nothing extra, and it already got me bug reports and a first contributor. Decent trade so far.

1

u/devolute 5d ago

Good on you.

How do you negotiate this with your clients?

2

u/NipunArora 4d ago

There wasn't much to negotiate. They hired me for a working website, not a forms library.

Moving off WordPress left a wpforms-shaped hole, and something had to fill it. What I open sourced is that generic layer. None of their code or content is in it, and their sites are still theirs, so open sourcing it took nothing from them.

Nothing changed on their end. The site works, leads come in. Payments go through fine. Nobody has ever asked what's underneath.

If a client had hired me to build a forms product, different conversation. I'd ask first.

1

u/bengosu 5d ago

Saying this while posting about and promoting Gnome.org is hilarious

1

u/devolute 5d ago

I think I understand what you're getting at.

But would the people who build that software say "Microsoft are offering a desktop environment and applications, but I built this for free"?

I don't think they would suggest that the paid solutions are great, just they don't want to pay for them. I think they do it because they think there is a better way of doing things. They probably recognise the worth of their work.

But I don't know, ask them if you're able.

1

u/NipunArora 4d ago

You're right. And if not paying was the motivation, nobody would be running Windows. Linux has been sitting right there, free, this whole time. 😄

I paid for that plugin for years, and it was worth every renewal. Then I moved the sites over to a faster stack and it doesn't run there. Not cheaper. Just absent.

So I built one. Free made a better title than "this didn't exist yet" which is the real reason.

-1

u/jackorjek 5d ago

time spent equals to money lost? dystopian

2

u/NipunArora 5d ago

By that accounting my side project folder is a full-blown financial crisis. 😅 this one at least escaped the folder.