netlify-access-control
Picks the right Netlify site-protection layer and disambiguates the three unrelated "auth" concepts users conflate — app-user…
Serverless form handling on Netlify-hosted sites — detects HTML forms at deploy time, stores submissions, filters spam, and sends notifications. Use when adding a contact form, lead-capture form, file-upload form, or newsletter signup to a Netlify site; wiring AJAX form
Claude Code
$ npx -y skills add netlify/context-and-tools --skill netlify-forms --agent claude-code
Codex
$ npx skills add netlify/context-and-tools --skill netlify-forms -a codex -y
Cursor
$ npx skills add netlify/context-and-tools --skill netlify-forms -a cursor -y
Gemini CLI
$ npx skills add netlify/context-and-tools --skill netlify-forms -a gemini-cli -y
GitHub Copilot
$ npx skills add netlify/context-and-tools --skill netlify-forms -a github-copilot -y
OpenCode
$ npx skills add netlify/context-and-tools --skill netlify-forms -a opencode -y
Windsurf
$ npx skills add netlify/context-and-tools --skill netlify-forms -a windsurf -y
name: netlify-forms description: Serverless form handling on Netlify-hosted sites — detects HTML forms at deploy time, stores submissions, filters spam, and sends notifications. Use when adding a contact form, lead-capture form, file-upload form, or newsletter signup to a Netlify site; wiring AJAX form submission; setting up a custom thank-you page; adding a honeypot or reCAPTCHA to a form; getting forms working in Next.js, Nuxt, SvelteKit, Astro, or Gatsby; reading form submissions via the Netlify API; setting up submission notifications or ChatGPT automations on form submission events; or debugging missing submissions and forms that silently fail to register.
Mark a form for detection with `data-netlify="true"` (or the bare `netlify` attribute — equivalent) on the `<form>` tag. Forms are detected by **parsing the final built HTML at deploy time** — there is no runtime API call or backend code. Client-side/JS-rendered/SSR forms are NOT in the built HTML and are never detected on their own; they require a static skeleton file (see below).
Prerequisite: form detection must be enabled once in the Netlify UI (Forms > **Enable form detection**). Takes effect on the next deploy.
<form name="contact" method="POST" data-netlify="true"> <p><label>Your Name: <input type="text" name="name" /></label></p> <p><label>Your Email: <input type="email" name="email" /></label></p> <p><label>Message: <textarea name="message"></textarea></label></p> <p><button type="submit">Send</button></p> </form>
Two required pieces:
**1. Static skeleton file `public/__forms.html`** — a hidden copy of each form with `data-netlify="true"`, a hidden `form-name` input, and every field the component submits, with names matching **exactly** (Netlify validates field names against the registered form). Without this file, submissions silently fail.
<!-- public/__forms.html --> <form name="pizzaOrder" data-netlify="true" hidden> <input type="hidden" name="form-name" value="pizzaOrder" /> <input name="order" type="text" /> </form>
**2. The rendered form** carries a matching hidden `form-name` input:
<form name="pizzaOrder" method="post" data-netlify="true" onSubmit={handleSubmit}>
<input type="hidden" name="form-name" value="pizzaOrder" />
<input name="order" type="text" onChange={handleChange} />
<input type="submit" />
</form>**⚠️ SSR POST target:** In SSR apps, `fetch("/")` is intercepted by the SSR catch-all function and never reaches form processing. POST to the static skeleton file itself — `/__forms.html` — not `/` or an arbitrary path.
**⚠️ Astro on-demand routes:** Routes with `export const prerender = false` or `output: "server"` are never scanned at build time, so their forms are never registered. Put the form on a prerendered page, or rely on the static skeleton file.
**Next.js Runtime v5 (Next.js 13.5+):** extract form definitions to the static skeleton file and submit via AJAX rather than full-page navigation. See https://docs.netlify.com/build/frameworks/framework-setup-guides/nextjs/overview#v5-breaking-changes
const handleSubmit = event => {
event.preventDefault();
const formData = new FormData(event.target);
fetch("/__forms.html", { // static sites may POST to "/"; SSR must target the skeleton file
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams(formData).toString()
})
.then(() => alert("Thank you for your submission")) // or navigate("/thank-you")
.catch(error => alert(error));
};
document.querySelector("form").addEventListener("submit", handleSubmit);Add `type="file"`; optionally `enctype="multipart/form-data"` on the `<form>`. For AJAX file uploads, **do NOT set a `Content-Type` header** — let the browser set it (with the multipart boundary).
document.forms.fileForm.addEventListener("submit", event => {
event.preventDefault();
fetch("/", { body: new FormData(event.target), method: "POST" }) // no headers
.then(() => { /* success */ });
});Limits: one file per field (use multiple fields for multiple files) · 8 MB max request size · 30 s upload timeout · after form deletion, uploaded files stay at their direct URL for 24 h. PII uploads need extra security (Very Good Security integration).
Add an `action` path relative to site root, starting with `/`. **Use extensionless paths** — Netlify serves `thank-you.html` at `/thank-you`; the `.html` path returns 404.
<form name="contact" action="/thank-you" method="POST" data-netlify="true"></form>
Custom success *alert* is only possible via AJAX (substitute the redirect with your own logic).
All submissions are filtered by Akismet. Passed → **Verified submissions**; flagged → **Spam submissions**. Honeypot/reCAPTCHA failures are rejected and appear in neither list.
**Honeypot:** add `netlify-honeypot="bot-field"` to the `<form>` and include a CSS-hidden field of that name. Any value entered → submission quietly rejected.
<form name="contact" method="POST" netlify-honeypot="bot-field" data-netlify="true"> <p class="hidden"><label>Don’t fill this out: <input name="bot-field" /
Public Netlify skills for AI coding agents. Each skill is a focused, factual reference for a Netlify platform primitive — designed to help agents build correctly on Netlify without needing to search docs.
Picks the right Netlify site-protection layer and disambiguates the three unrelated "auth" concepts users conflate — app-user…
Run AI agent tasks remotely on Netlify using Claude, Codex, or Gemini. Use when the user wants to run an AI agent on their site,…
Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models…
Store and retrieve unstructured objects, files, and cache-like state on Netlify with the @netlify/blobs module. Use when…
Cache dynamic and static responses on Netlify's CDN from Functions, Edge Functions, and proxies. Use when you add caching or…
Configure Netlify builds and routing via netlify.toml, _redirects, and _headers. Use when setting a build command or publish…
Use this skill whenever the user mentions Horizon by name in a Laravel context. Covers the full Horizon lifecycle: installing…
Use when launching cloud VMs, Kubernetes pods, or Slurm jobs for GPU/TPU/CPU workloads, training or fine-tuning models on cloud…
Use this skill when the user mentions "pinme", or needs to upload files, store to IPFS, create/publish/deploy websites or…