SheetLink Forms beta

Plain HTML forms to Google Sheets

One action attribute, zero backend. Your static site's form posts to a permanent endpoint and every submission lands as a row in your sheet.

A plain HTML form is still the most durable way to collect a lead: no framework, no build step, nothing to break. The part that has always been missing is the backend - something has to receive the POST, screen it, and file it somewhere useful. SheetLink Forms is that backend. You point your form's action at a permanent endpoint of the shape https://sheetlinkforms.com/f/{token}, and each submission lands as a row in Google Sheets or an Excel Online table.

There is no middleman in the path. An asynchronous worker writes directly to the Google Sheets API or Microsoft Graph - no Zapier, no automation tool replaying webhooks - and retries at 5 minutes, 30 minutes, and 2 hours cover transient failures. Every attempt shows up in a delivery log in the dashboard, so you never have to wonder whether a lead made it into the ledger. There are no per-submission fees, ever.

You can watch exactly this setup running on the live demo, where a real form feeds a public sheet. SheetLink Forms is free during beta and invite-gated - join the waitlist to get an endpoint.

The best path for Plain HTML

The best path for a static site is also the simplest: set action to your endpoint and method to POST. The browser does the rest. The endpoint accepts standard urlencoded form posts (bodies capped at 256KB) and answers with a 303 redirect to a hosted thank-you page, or to any custom redirect URL you configure. No JavaScript is required at all.

If you want more, add the optional sl.js embed. It upgrades the same form to an AJAX submit with inline success text, auto-injects the honeypot, adds a timing signal used in spam screening, and captures utm_source, utm_medium, utm_campaign, utm_term, and utm_content plus the gclid, wbraid, gbraid, fbclid, and msclkid click IDs from the URL - persisted in localStorage so attribution survives page-to-page browsing before the visitor finally submits.

<!-- The whole integration: point action at your endpoint --> <form action="https://sheetlinkforms.com/f/slf_yourtoken" method="POST"> <input type="text" name="Name" required> <input type="email" name="Email" required> <textarea name="Message"></textarea> <!-- Honeypot: keep it exactly as-is; visitors never see it --> <input name="_slhp" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px"> <button type="submit">Send</button> </form> <!-- Optional: AJAX submit + ad attribution, one script tag --> <script src="https://sheetlinkforms.com/sl.js" data-token="slf_yourtoken"></script>

1. Connect a sheet and get your endpoint

Sign in and connect Google Sheets with one-click OAuth. The connection uses the drive.file scope, which means SheetLink Forms can only touch sheets you pick in the Google picker or create inside the product - never the rest of your Drive. Prefer Microsoft 365? Connect Excel Online instead and pick an Excel table; the table's columns define the row shape. Either way you get a permanent endpoint at https://sheetlinkforms.com/f/{token}.

2. Point your form at the endpoint

Set action to the endpoint and method="POST". Name your inputs after your column headers and the mapping happens automatically - matching is case and punctuation insensitive, so Email, email, and E-mail all land in an Email column. If your field names and headers genuinely differ, explicit per-field mapping is available in the dashboard.

3. Add the honeypot input

Copy the _slhp input from the snippet above. It sits off-screen where humans never see it, so anything that fills it is a bot - the honeypot is the only signal that marks spam outright. Everything else that looks suspicious (rate-limit trips, content heuristics, timing anomalies) is quarantined for one-click review instead, so a false positive costs you seconds, not a lead. Details are in the docs.

4. Optionally add sl.js

Drop the script tag before </body>. It binds any form whose action points at /f/ (and any form marked data-sheetlink), converts it to an AJAX submit with inline success text, injects the honeypot for you, adds the timing signal, and captures UTM parameters and ad click IDs. If you skip it, the plain 303-redirect flow still works exactly as before.

5. Submit a test and read the delivery log

Send a test submission. On an empty sheet the header row is seeded for you; after that, rows append under the header, aligned to your columns. The delivery log in the dashboard shows each attempt, and a formula-injection guard escapes leading =, +, -, and @ characters so a hostile submission cannot become a live formula in your ledger. The full flow is on how it works.

FAQ

Do I need any JavaScript at all?

No. A bare action + method="POST" form works with JavaScript disabled: the endpoint accepts the urlencoded post and answers with a 303 redirect to a thank-you page or your custom redirect URL. sl.js is strictly optional - it adds inline success handling and ad attribution, but the form does not depend on it.

What does the visitor see after submitting?

Without sl.js, the browser follows a 303 redirect to a hosted thank-you page or any custom URL you set per form. With sl.js, the page does not navigate at all - the form swaps to inline success text, which you can customize.

How is spam handled when I have no backend of my own?

Several layers run on the endpoint itself: the _slhp honeypot, per-form and per-IP rate limits, an optional per-form origin allowlist, content heuristics (link stuffing, disposable email domains, empty payloads) with a per-form strictness dial, the sl.js timing signal, and optional Cloudflare Turnstile. Suspicious submissions are quarantined for one-click review - approve delivers the row - and never silently dropped.

Can a submission break my spreadsheet formulas?

No. A formula-injection guard escapes leading =, +, -, and @ in cell values before rows are written, so pasted payloads stay inert text in the cell.

What does it cost?

SheetLink Forms is free during beta; an invite is required, so join the waitlist. Planned post-beta pricing is a free tier around 50 submissions a month and a paid plan around $15-19/mo, unmetered. There are no per-submission or per-task fees, ever - that part is not planned, it is policy.

Also on: Next.js · React · Carrd

Request an invite See the live demo