Update to Netlify
Snapshot Sep 30, 2026 · 23:18 UTC · version 1.0.0
Collection source: not recorded for this historical snapshot. These snapshots do not have a confirmed matching collection source. Differences in file lists alone do not establish changes to the package.
Supporting file metadata differs
Newly listed paths: LICENSE.txt, agents/openai.yaml. This compares saved file lists, not package contents; a different collection source can change the list.
Observed in package metadata. These changes alone do not establish a new customer-facing feature.
Supporting files
[{"relative_path":"assets/netlify-small.svg","size_in_bytes":1291},{"relative_path":"assets/netlify.png","size_in_bytes":2686}]
[{"relative_path":"LICENSE.txt","size_in_bytes":10776},{"relative_path":"agents/openai.yaml","size_in_bytes":332},{"relative_path":"assets/netlify-small.svg","size_in_bytes":1291},{"relative_path":"assets/netlify.png","size_in_bytes":2686}]
Compare saved observations
Download comparison JSONFull technical diff · 1 changed fields
changed /included_files
[
{
"relative_path": "assets/netlify-small.svg",
"size_in_bytes": 1291
},
{
"relative_path": "assets/netlify.png",
"size_in_bytes": 2686
}
][
{
"relative_path": "LICENSE.txt",
"size_in_bytes": 10776
},
{
"relative_path": "agents/openai.yaml",
"size_in_bytes": 332
},
{
"relative_path": "assets/netlify-small.svg",
"size_in_bytes": 1291
},
{
"relative_path": "assets/netlify.png",
"size_in_bytes": 2686
}
]Full snapshot data
{
"name": "netlify-forms",
"description": "Guide for using Netlify Forms for HTML form handling. Use when adding contact forms, feedback forms, file upload forms, or any form that should be collected by Netlify. Covers the data-netlify attribute, spam filtering, AJAX submissions, file uploads, notifications, and the submissions API.",
"included_files": [
{
"relative_path": "LICENSE.txt",
"size_in_bytes": 10776
},
{
"relative_path": "agents/openai.yaml",
"size_in_bytes": 332
},
{
"relative_path": "assets/netlify-small.svg",
"size_in_bytes": 1291
},
{
"relative_path": "assets/netlify.png",
"size_in_bytes": 2686
}
],
"skill_md_contents": "---\nname: netlify-forms\ndescription: Guide for using Netlify Forms for HTML form handling. Use when adding contact forms, feedback forms, file upload forms, or any form that should be collected by Netlify. Covers the data-netlify attribute, spam filtering, AJAX submissions, file uploads, notifications, and the submissions API.\n---\n\n# Netlify Forms\n\nNetlify Forms collects HTML form submissions without server-side code. Form detection must be enabled in the Netlify UI (Forms section).\n\n## Basic Setup\n\nAdd `data-netlify=\"true\"` and a unique `name` to the form:\n\n```html\n<form name=\"contact\" method=\"POST\" data-netlify=\"true\">\n <label>Name: <input type=\"text\" name=\"name\" /></label>\n <label>Email: <input type=\"email\" name=\"email\" /></label>\n <label>Message: <textarea name=\"message\"></textarea></label>\n <button type=\"submit\">Send</button>\n</form>\n```\n\nNetlify's build system detects the form and injects a hidden `form-name` input automatically. For a custom success page, add `action=\"/thank-you\"` to the form tag. Use paths without `.html` extension — Netlify serves `thank-you.html` at `/thank-you` by default, and the `.html` path returns 404.\n\n## JavaScript-Rendered Forms (React, Vue, SSR Frameworks)\n\nFor forms rendered by JavaScript frameworks (React, Vue, TanStack Start, Next.js, SvelteKit, Remix, Nuxt), Netlify's build parser cannot detect the form in static HTML. You MUST create a static HTML skeleton file for build-time form detection:\n\nCreate a static HTML file in `public/` (e.g. `public/__forms.html`) containing a hidden copy of each form:\n\n```html\n<!DOCTYPE html>\n<html>\n <body>\n <form name=\"contact\" data-netlify=\"true\" netlify-honeypot=\"bot-field\" hidden>\n <input type=\"hidden\" name=\"form-name\" value=\"contact\" />\n <input type=\"text\" name=\"name\" />\n <input type=\"email\" name=\"email\" />\n <textarea name=\"message\"></textarea>\n <input name=\"bot-field\" />\n </form>\n </body>\n</html>\n```\n\n**Rules:**\n- The form `name` must exactly match the `form-name` value used in your component's fetch call\n- Include every field your component submits — Netlify validates field names against the registered form\n- Without this file, Netlify cannot detect the form and submissions will silently fail\n\nYour component must also include a hidden `form-name` input:\n\n```jsx\n<form name=\"contact\" method=\"POST\" data-netlify=\"true\">\n <input type=\"hidden\" name=\"form-name\" value=\"contact\" />\n {/* ... fields ... */}\n</form>\n```\n\n## AJAX Submissions\n\n### Vanilla JavaScript\n\n```javascript\nconst form = document.querySelector(\"form\");\nform.addEventListener(\"submit\", async (e) => {\n e.preventDefault();\n const formData = new FormData(form);\n await fetch(\"/\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams(formData).toString(),\n });\n});\n```\n\n> **SSR frameworks (TanStack Start, Next.js, SvelteKit, Remix, Nuxt):** The `fetch` URL must target the static skeleton\n> file path (e.g. `\"/__forms.html\"`), **not** `\"/\"`. In SSR apps, `fetch(\"/\")` is intercepted by the SSR catch-all\n> function and never reaches Netlify's form processing middleware. See the React example and troubleshooting section below.\n\n### React Example\n\n```tsx\nfunction ContactForm() {\n const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n // For SSR apps, use the skeleton file path instead of \"/\" (e.g. \"/__forms.html\")\n const response = await fetch(\"/__forms.html\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams(formData as any).toString(),\n });\n if (response.ok) {\n // Show success feedback\n }\n };\n\n return (\n <form name=\"contact\" method=\"POST\" data-netlify=\"true\" onSubmit={handleSubmit}>\n <input type=\"hidden\" name=\"form-name\" value=\"contact\" />\n <input type=\"text\" name=\"name\" placeholder=\"Name\" />\n <input type=\"email\" name=\"email\" placeholder=\"Email\" />\n <textarea name=\"message\" placeholder=\"Message\" />\n <button type=\"submit\">Send</button>\n </form>\n );\n}\n```\n\n> **SSR troubleshooting:** If form submissions appear to succeed (200 response) but nothing shows in the Netlify Forms\n> UI, the POST is likely being intercepted by the SSR function. Ensure `fetch` targets the skeleton file path (e.g.\n> `\"/__forms.html\"`), not `\"/\"`. The skeleton file path routes through the CDN origin where Netlify's form handler runs.\n\n## Spam Filtering\n\nNetlify uses Akismet automatically. Add a honeypot field for extra protection:\n\n```html\n<form name=\"contact\" method=\"POST\" netlify-honeypot=\"bot-field\" data-netlify=\"true\">\n <p style=\"display:none\">\n <label>Don't fill this out: <input name=\"bot-field\" /></label>\n </p>\n <!-- visible fields -->\n</form>\n```\n\nFor reCAPTCHA, add `data-netlify-recaptcha=\"true\"` to the form and include `<div data-netlify-recaptcha=\"true\"></div>` where the widget should appear.\n\n## File Uploads\n\n```html\n<form name=\"upload\" enctype=\"multipart/form-data\" data-netlify=\"true\">\n <input type=\"text\" name=\"name\" />\n <input type=\"file\" name=\"attachment\" />\n <button type=\"submit\">Upload</button>\n</form>\n```\n\nFor AJAX file uploads, use `FormData` directly — do **not** set `Content-Type` (the browser sets it with the correct boundary):\n\n```javascript\nawait fetch(\"/\", { method: \"POST\", body: new FormData(form) });\n```\n\n**Limits:** 8 MB max request size, 30-second timeout, one file per input field.\n\n## Notifications\n\nConfigure in the Netlify UI under **Project configuration > Notifications**:\n\n- **Email**: Auto-sends on submission. Add `<input type=\"hidden\" name=\"subject\" value=\"Contact form\" />` for custom subject lines.\n- **Slack**: Via Netlify App for Slack.\n- **Webhooks**: Trigger external services on submission.\n\n## Submissions API\n\nAccess submissions programmatically:\n\n```\nGET /api/v1/forms/{form_id}/submissions\nAuthorization: Bearer <PERSONAL_ACCESS_TOKEN>\n```\n\nKey endpoints:\n\n| Action | Method | Path |\n|---|---|---|\n| List forms | GET | `/api/v1/sites/{site_id}/forms` |\n| Get submissions | GET | `/api/v1/forms/{form_id}/submissions` |\n| Get spam | GET | `/api/v1/forms/{form_id}/submissions?state=spam` |\n| Delete submission | DELETE | `/api/v1/submissions/{id}` |\n"
}SHA-256: bf51472112e3ea3530195098500c5dcb1047fc06fb3ac5825ecb729f605f0948