by philwonski  • February 22, 2022

Serverless Form Submissions the Low-Code Way

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.

Depiction of the setup, with a single-page TiddlyWiki used for serverless form submissions, and POSTs caught by Pipedream.
In this tutorial, I will quickly build a web form for serverless form submissions using the low-code TiddlyWiki platform. Then I’ll host it on Cloudflare pages, and collect form submissions with 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.

Built entirely in the browser with TiddlyWiki, this Jamstack form is a slick single page application, and allows for serverless form submission of user inputs.

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

Showing two different forms available, based on the condition set in the greeting form.
The app will present the appropriate sign up form based on the condition you set in the greeting form (the sport preference). The user inputs are stored in the browser and then the serverless form submission can be made with a POST request.

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

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 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.

The greeting form uses “action widgets” to set the state of the app before form submission.

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 ski form is shown because the user selected skiing in the greeting form.
The Ski Form is shown based on the user’s selection in the Greeting Form. The state of the application (the user’s input) is stored 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 Surf Form is shown based on the user’s selection in the Greeting Form. The state of the application (the user’s input) is stored in the state/selections tiddler.
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.

The state/selections tiddler stores the state of the user inputs in json, useful later for severless form submission.
The state/selections tiddler is used to store the user’s inputs in json, useful later for serverless form submission.
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:

Building the submit button for serverless form submission using a POST request.
POSTing serverless form data to an API endpoint. The endpoint is set in the field 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:

Adding a new question to the Surf Form before we test serverless form submission.
Adding a new question to the Surf Form before we test serverless form submission.

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.”

Setting up a simple HTTP endpoint "listener" to receive WordPress form submissions via webhooks.
Setting up a simple HTTP endpoint “listener” to receive form submissions.

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") {
  status: 200,
  headers: { "content-type": "text/html; charset=UTF-8", "access-control-allow-origin" : "*" },
  body: { message: "Received!" },
  return "Origin verified"
} else {
  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.

Setting the serverless form submission listener via a Pipedream endpoint.
Serverless form submission listener via a Pipedream endpoint.

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.

Showing the POST request from the serverless form submission to the Pipedream endpoint.
POST request from the serverless form submission to the Pipedream endpoint.

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!

Showing Pipedream receiving the jamstack form submission.
Pipedream is an excellent Jamstack form listener.
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:

  1. Dev Repo – houses the tiddlywiki source files.
  2. 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!

TiddlyWiki creates the index.html file, a single page application out of your form.
TiddlyWiki creates a single page application out of 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.