April 1, 2023
READING TIME5 min

Introducing Notiflare Forms

We're excited to introduce NotiFlare Forms, an open-source project that streamlines connecting your forms to a Notion database using Cloudflare Workers.

When we started this website, we needed an inexpensive server to handle form data from our "contact us" page. We didn't want to grapple with a database or an expensive SaaS product (e.g. Netlify Forms). And we couldn't rely on the backend serving this site because it's tied to Cloudflare's limited Cloudflare Pages.

Since Notion powers most of our business and has a convenient public API, we thought that was our best option. After an hour, we had an MVP out:

import { Client } from "@notionhq/client"
function error(errors: string[]): Response {
return new Response(JSON.stringify({ errors, success: false }), {
headers: {
'Content-type': 'application/json'
}
});
}
interface Submission {
name: string;
email: string;
message: string;
databaseID: string;
}
function notionPage({ databaseID, name, email, message }: Submission): any {
return {
parent: {
database_id: databaseID
},
properties: {
"Title": {
"title": [
{
"text": {
"content": 'Form Submission'
}
}
]
},
"Email": {
"email": email
},
"Name": {
"rich_text": [
{
"text": {
"content": name
}
}
]
},
},
children: [
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": message
}
}
]
}
}
]
}
}
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
if (request.method.toUpperCase() !== "POST") {
return error(["Only POST requests allowed."])
}
const formData = await request.formData()
const name = formData.get("name")
const message = formData.get("message")
const email = formData.get("email")
if ([name, message, email].filter((f: string|null|File) => !f).length > 0) {
return error(["name, message, and email fields must contain a value."])
}
try {
const notion = new Client({
auth: env.NOTION_INTEGRATION_TOKEN,
})
await notion.pages.create(
notionPage({
databaseID: env.NOTION_DATABASE_ID,
name: name as string,
email: email as string,
message: message as string
})
)
return new Response(null, {
status: 204,
});
} catch(e: any) {
return error([String(e)])
}
},
};

We sought to address two main problem points after the MVP in the project, which ChatGPT dubbed "Notiflare Forms":

  1. Since we can pull the database schema from Notion's API, the user should not have to define the schema themselves in code.
  2. With multipart/form-data, we can support file uploads.

How NotiFlare Forms Works

NotiFlare Forms uses Cloudflare Workers to manage form submissions, with a Notion database acting as a persistent store. To set it up, create a Notion integration, a Notion database with columns corresponding to your form's fields (or vice-versa), deploy a Cloudflare Worker, and point your form (or request) to the deployed Cloudflare worker.

After configuring the Cloudflare Worker and directing your form to the worker's URL, every valid submission will appear as a new entry in your Notion database.

On a form submission (or really any multipart/form-data POST request), NotiFlare Forms will do three primary things:

  1. Verify the submission contains the configured NOTION_REQUIRED_COLUMNS.
  2. Upload any files to an R2 bucket, if configured.
  3. Create a new Notion database entry page.

Demo

Demonstration of NotiFlare Forms

In the demo, we used the following HTML form pointed towards our Cloudflare worker. The Name, Message, and Attachments fields correspond to our Notion database's column names.

<form
method="POST"
action="https://our-cloudflare-worker/"
enctype="multipart/form-data"
>
<label>
Name
<input type="text" name="Name" required />
</label>
<label>
Message
<textarea type="text" name="Message" required></textarea>
</label>
<label>
Attachments
<input type="file" multiple="" name="Attachments"/>
</label>
<button type="submit">Send</button>
</form>

Benefits of NotiFlare Forms

  • Simplicity: No need to set up and manage servers or databases. NotiFlare Forms takes care of everything for you.
  • Flexibility: Design your form however you like and match the column names in your Notion database to your form's field names.
  • Cost-effective: Cloudflare Workers and Notion offer free tiers, making it possible to run your form backend without incurring any costs.
  • Scalability: Cloudflare Workers can handle many requests, ensuring your form backend can scale with ease.

Upcoming Enhancements

We're excited about growing and improving this project further. Here are a few enhancements we have in mind for the future:

  1. Presently, NotiFlare Forms supports only one Notion database per Cloudflare worker. However, there are no technical limitations that prevent us from accommodating multiple Notion databases.
  2. Notion's database API requires a Notion user ID for the People column type, and as such NotiFlare Forms expects the same to be submitted through the form. We aim to enable NotiFlare Forms to look up the user ID on Notion when provided with an email address.
  3. While we appreciate Cloudflare, it shouldn't be an essential requirement for running this project. As such, we plan to add support for AWS Lambda hosting. We also intend to support all S3-compatible APIs for file uploads to broaden developer options.

Getting Started

To get started with NotiFlare Forms, head over to the GitHub repository and follow the instructions in the README.


We'd love to hear your feedback, so if you have any questions or suggestions, please don't hesitate to reach out by creating a GitHub issue or using our contact form!

FIN.