Following up on our preferred plugin stack for WordPress forms, we bring you our favorite Jamstack solution for serverless form submissions.
If you’re here, you know the drill: we can send tourists into space, but we still make website forms like it’s 1999.
For the simplest forms, there’s no shortage of online tools — but what about when you need something custom, like a form with conditional logic? In this tutorial, I’ll go through how we set up these serverless forms quickly using our top two low-code tools, TiddlyWiki and Pipedream.

Why Jamstack forms?
Serverless Jamstack forms are attractive for the same reason static sites are useful generally: we don’t need to set up a server-based monolith like WordPress just to serve and manage a form.
Additionally, creating conditional logic in your forms can be a challenge with the typical options:
- In the WordPress ecosystem: conditional form logic in WordPress always requires a clunky plugin, and usually a paid add-on.
- In the SaaS ecosystem: conditional logic isn’t available in the more user-friendly tools like Google Forms and Airtable Forms; and more capable tools like Typeform lock you into their platform and their pricing plans, limiting the control you have over the total user experience.
So, if you really want to control what the user sees when she fills out your online form, you’ve got to go custom. But what’s that mean? How do we build frontend forms, manage state, POST data, then actually do something with the data when it comes in? Sounds daunting!
Serverless form submissions
Luckily, building custom frontend form experiences doesn’t require you to be a Javascript wiz kid. Thanks to the low-code powerhouse TiddlyWiki, we can build and test stateful frontend forms in minutes.
Check out this form as an example.

Depending on which sport you’re into, you are presented with a different set of questions.

To create the form, I used TiddlyWiki’s WikiText syntax. In just a few minutes, WikiText allowed me to create buttons and styles, and store the state of the user’s input. The following steps assume you will borrow the basic Wikitext form template from the example by cloning the Github repo.
1. Install TiddlyWiki and clone the example Wiki to your local machine.
First, we need to install TiddlyWiki on our machine and clone the example form. The only prerequisite for TiddlyWiki is Node/NPM itself.
sudo npm install -g tiddlywiki
git clone git@github.com:philwonski/TW5-Serverless-Form-Submission.git
To edit the form locally in our web browser, we can launch TiddlyWiki as follows:
cd TW5-Serverless-Form-Submission
tiddlywiki --listen port="8318"
Then visit http://127.0.0.1:8318/
in your browser.
Low-code form builder
TiddlyWiki’s low-code Wikitext sytax made the serverless form creation a breeze. Each object (or “tiddler”) in the wiki contains a bit of Wikitext to build the form experience, similar to a view or a component in other frameworks.
The point of this whole exercise is that this user experience can be built so rapidly, with just the handful of low-code tiddlers described below.
Greeting Form Tiddler
The greeting tiddler creates the greeting screen of the form. It has pictures of sports. Clicking a sport sets the state of the application to that sport.

Note the Wikitext “action widget” I’ve used to store the user’s selection in another tiddler called state/selections
:
<$action-setfield $tiddler="state/selections" $index="sport" $value="surfing" />
So all we are saying here is, “if you click this button (the image), set sport to skiing (or surfing).” The succinctness of the Action widget to store any state is what makes learning this tool worth the investment. Wikitext allows us to collect — and validate — user input in all sorts of creative ways.
The Ski Form
If the state of the application is set to skiing, that action is logged and this Skiing form is displayed.
Here again, we can see that I am storing the state in the state/selections
tiddler.

The Surf Form
Since the idea is to show the serverless form submission when a form has conditional logic, you can see that the Surf Form is different than the Ski Form.
That is, if you select the “Surfing” condition, the form changes.

The state/selections tiddler
Since tiddlers are just objects, we can store any key-value pairs we want in them. This makes Jamstack form creation a breeze because we can quickly create little json databases.

Submit button
Finally, we’ve got to do something with that neat bit of json we created on the frontend. We’ve got to submit the form! That is, we’ve got to POST the data out to an endpoint.
In TiddlyWiki, my go-to plugin for sending POST requests is Ooktech’s Submit Form plugin. When you clone my repo, the Submit Form plugin is included, with a minor modification to post json payloads instead of encoded URLs.
With the Submit Form plugin in place, we can post our json state tiddler out to the web directly as follows:

url
of the tiddler endpoint
. This tiddler calls the javascript plugin to make xhr requests, and POSTS the data from your state/selections
file to your form’s API endpoint.
2. Add a question to your form.
In the screenshots above, I created the TiddlyWiki form right there in the browser by serving the Wiki locally with the listen
command.
tiddlywiki --listen port="8318"
But for quick edits, such as to add a quick question to one of the forms, we can also just edit the tiddlers directly in a text editor.
If I open up Surf Form.tid
for example, I can easily drop in an important question for all would-be surfers:

Serverless form data handling
Now that we’ve got the form the way we want it, it’s time to go about the business of actually collecting user submissions.
At Digital Mark, we have standardized virtually all of our form submissions to reach endpoints on Pipedream. If you haven’t heard of Pipedream, it’s a Zapier alternative designed for developers. We’ll use Pipedream to set up a special URL where Pipedream will “listen” for form submissions.
3. Create an endpoint for receiving data.
Pipedream makes it super easy to get started. Just sign up, then click Workflows
in the left pane and the New +
button in the top right. Once you do that, you’ll see that creating an HTTP endpoint is the first option on the top right when selecting a type of “trigger.”

Triggers are just the way to kick off the steps in your workflow in response to an event. In our case:
- The events will be form submissions;
- the trigger will be when the form submission hits our endpoint URL;
- and the workflow will be a series of steps we take with the data when it comes in (like sending you a notification, or adding an email address to Mailchimp).
Since Pipedream doesn’t have a built-in way to verify the origin of our request, it’s good to do that as a first step in our workflow. This is just some basic security to protect your form endpoint, since the endpoint URL will be visible in your code. After the endpoint is created, click the plus sign and create a new node.js step with the following code. If you don’t have a domain for your form yet, you’ll need to come back here once you deploy the form and replace the domain in the if
statement.
// get the origin header from the request
var origin = steps.trigger.event.headers.origin;
// if it matches my origin, respond 200; else, 403
if (origin === "DOMAIN-OF-MY-FORM") {
$respond({
status: 200,
headers: { "content-type": "text/html; charset=UTF-8", "access-control-allow-origin" : "*" },
body: { message: "Received!" },
});
return "Origin verified"
} else {
$respond({
status: 403,
headers: { "content-type": "text/html; charset=UTF-8", "access-control-allow-origin" : "*" },
body: { message: "Wrong origin. Easy there, buddy!" },
});
$end("wrong origin")
}
4. Save endpoint URL in TiddlyWiki and test serverless form submission.
Now that we have created an endpoint URL, we need to use that URL in our form, so the form knows where to send our data.
In my Github repo example, I provided a convenient place to set the endpoint URL in the sidebar on the right.

Alternatively, you can also edit the tiddler endpoint.tid
directly. Just paste your endpoint value after the url:
key.
Now that your form is ready and your endpoint is set, you can test the submission locally right in your browser.

Back in Pipedream, we can see that our form submission came in nicely. We can now take the data from that JSON payload and do whatever we’d like with it!

5. Push the form to prod with Cloudflare Pages.
So, you’ve got a working form, and you’ve got a working serverless form listener. Now how do we actually publish our little app?
Usually, for serverless form submissions, I lean toward Cloudflare pages. I’m a big believer in the Cloudflare platform, and the Cloudflare pages product is similar to Netlify and other Jamstack hosts: it’s super fast, and all you have to do is push a git repo to deploy.
For TiddlyWiki Jamstack forms, I usually set up two git repos:
- Dev Repo – houses the tiddlywiki source files.
- Prod Repo – houses the single-file static HTML output of my wiki.
To create a prod repo, we’ll want to package all of our individual tiddler components into a single page application. TiddlyWiki makes this easy:
tiddlywiki --build index
Now, navigate to your wiki’s output
folder, and you will find an index.html file. That’s your form!

In a new directory, drop your index.html file and initialize a new git repo. Set up Cloudflare pages for the repo, then push it to Github and you’re all set!
Up Next: Serverless Image Upload with Lambda and API Gateway
At the end of the day, it doesn’t really matter how you create a JSON payload on the frontend. I just showed you how I like to do it with a low-code tool, because I love TiddlyWiki and it’s so quick!
Likewise, there are numerous ways to go about collecting file uploads from users in the frontend. Large files? You’ll want to look at pre-signed S3 URLs. But what about just images, such as a receipt image or similar? How can we handle these in the frontend and get them into the backend?
In a follow-up tutorial, I’ll be calling on TiddlyWiki again to do just that — stage an image in json in the frontend, store the state, then POST the data to an endpoint for processing later. Kewwl.
If you liked this post, follow me on Twitter @philwonski so you know when I post similar content. You can see past posts by me here.
There’s also lots of great (and less esoteric) content being produced by our team on a regular basis — be sure to find us on LinkedIn, and sign up to our newsletter in the footer of this page.