formseal-embed is a drop-in utility for client side encrypted contact forms. You drop it in, it encrypts submissions in the browser before they're sent, and your backend receives ciphertext it can decrypt on its own terms.
That's the pitch. The reality is I had a working version of this before the rewrite and it drove me insane. Every time I touched it I was thinking about Cloudflare. Cloudflare KV. Cloudflare Workers. The challenge/verify pipeline. It worked, but it was a house of cards. One config change upstream and everything downstream quietly broke.
So I started over. And the whole rewrite was basically one question on repeat: does this belong here, or am I just rebuilding the thing I hated?
The only real constraint
I gave myself one rule going in: it has to work with any endpoint that accepts a POST request. That's it. No assumptions about the backend, no vendor-specific hooks, no "but it's optimized for X." If you've got a URL, it works.
That constraint sounds simple but it changes everything. It means the embed can't do clever backend stuff. It means the CLI can't assume what platform you're on. It means every feature I wanted to add had to pass the test: does this break vendor agnosticism? A lot of them didn't survive.
The embed does less than you'd expect : on purpose
My first instinct was to make the embed smart. Field-level validation, custom error messages, auto-generated markup. But every time I built one of those things I was making decisions that belonged to the developer using the tool, not me.
So I cut it back. The embed reads name attributes, manages button state, encrypts the payload, and posts it. That's all it touches. You own all the HTML. If that sounds limiting, it's actually the point: it means formseal-embed works with whatever form structure you already have.
Why the CLI is Python and not rust or go
I thought about this way too long. Rust felt right - fast, single binary, no runtime. Go too. But I kept coming back to the same mental image: someone running fse init for the first time, on whatever machine they have, with whatever they've got installed.
Python is almost certainly already there. No build step, no toolchain to install, no "wait let me install Rust first." Zero friction is the right tradeoff for a setup CLI. The tool should get out of the way.
What's coming: fse doctor
One thing I kept running into during testing - a small misconfiguration breaks everything silently. Wrong endpoint, bad public key, and you get nothing useful back. Debugging it was miserable.
So I'm building fse doctor. The idea: run it after fse init and it checks your whole setup; config, endpoint reachability, public key validity, schema fields etc and tells you exactly what's broken and what command to run to fix it. No vague errors, no guessing.
It's not out yet, but it's in the works. It's the kind of thing that should've existed from the start.
The thing I kept having to resist
The hardest part of the rewrite wasn't the crypto or the CLI structure. It was resisting the urge to add things. Every feature that seemed reasonable in isolation was pulling the tool back toward being opinionated about your backend, or your platform, or your validation logic.
Vendor agnosticism isn't a feature you add. It's a constraint you enforce by saying no to a lot of reasonable ideas.
Come take a look
The package is @formseal/embed on npm. Source is at github.com/grayguava/formseal-embed.
If you have thoughts on what fse doctor should check, what the CLI is missing, or just want to poke around the encryption pipeline: issues and PRs are open. Would love to hear what other people think is worth validating before a form goes live.
Have you dealt with the vendor-lock problem with third-party form tools? Did you work around it or just accept it and move on? Genuinely curious.
Top comments (0)