форми

Форми, які працюють без бекенду

Додайте один атрибут до форми на своєму статичному сайті — і кожна відповідь потрапить до вашої панелі керування. Без JavaScript, без вбудованих віджетів, без сторонніх сервісів, і тому, хто заповнює форму, ніде не треба реєструватися.

Its markup, styles and deploy script are on GitHub — copy it, change the fields, redeploy.

index.html
<form harvis-form="contact">
  <input name="email" type="email" required>
  <textarea name="message"></textarea>
  <button>Send</button>
</form>
how it works

Три кроки, і один з них — просто розгорнути сайт ще раз

Немає конструктора форм, який довелося б вивчати, і немає ендпоїнта, який треба скопіювати. Атрибут — це і є все налаштування.

  1. 01

    Додайте атрибут

    Впишіть harvis-form у будь-яку форму у вашому HTML. Дайте їй назву, якщо на сайті форм більше однієї. Action і method можна не вказувати — вони підставляються, коли сторінка віддається браузеру.

  2. 02

    Розгорніть ще раз

    Перетягніть папку знову або виконайте npx harvis. Нічого не треба налаштовувати, не треба вставляти жодного ключа й попередньо вмикати перемикач у панелі керування.

  3. 03

    Читайте те, що надходить

    Відповіді з'являються під вашим сайтом у панелі керування, найновіші згори. Відкрийте рядок, щоб прочитати все, або заберіть усе разом у CSV.

the markup

Усе зводиться до двох атрибутів

harvis переписує форму дорогою з сервера, тож сторінка, яку ви написали, залишається сторінкою, яку ви написали.

що пишете ви
<form harvis-form="contact"
      data-harvis-redirect="/thanks.html">
  <input name="email" type="email" required>
  <button>Send</button>
</form>
що отримують ваші відвідувачі
<form harvis-form="contact"
      data-harvis-redirect="/thanks.html"
      action="/__harvis/form/contact" method="post">
  <input type="hidden" name="_harvis_redirect" value="/thanks.html">
  <input type="text" name="_harvis_hp" tabindex="-1" aria-hidden="true" style="…">
  <input name="email" type="email" required>
  <button>Send</button>
</form>

Ці два атрибути

harvis-form
Позначає форму як таку, з якої треба збирати відповіді. Значення дає їй назву, щоб кілька форм на одному сайті не змішувалися; якщо значення не вказати, відповіді збираються під назвою «default».
data-harvis-redirect
Необов'язковий. Сторінка вашого сайту, на яку потраплять люди після надсилання. Усе, що вказує за межі вашого сайту, ігнорується.
frameworks

Якщо форму будує JavaScript, впишіть ендпоїнт самі

harvis підставляє action тоді, коли сторінка залишає сервер. Форми, яка з'являється лише після запуску вашого бандла, у сторінці ще немає — тож підставляти нема куди, і ви пишете те, що написало б переписування. Це все одно звичайний HTML-post, і решта цієї сторінки так само чинна.

  • React
  • Vue
  • Svelte
  • Angular
ContactForm.jsx
<form action="/__harvis/form/contact" method="post">
  <input name="email" type="email" required />
  <textarea name="message" />

  {/* optional — where to land after sending */}
  <input type="hidden" name="_harvis_redirect" value="/thanks" />

  {/* optional — the decoy harvis would have added */}
  <input
    type="text"
    name="_harvis_hp"
    tabIndex={-1}
    autoComplete="off"
    aria-hidden="true"
    style={{ position: "absolute", left: "-9999px", opacity: 0 }}
  />

  <button>Send</button>
</form>
action + method
Ендпоїнт, який написав би harvis, плюс post. Останній сегмент — назва форми: маленькі літери, цифри й дефіси; усе інше збирається під «default».
_harvis_redirect
Необов'язково, і це написана вручну версія data-harvis-redirect. Шлях на вашому ж сайті; усе, що веде за його межі, ігнорується.
_harvis_hp
Необов'язково, і це єдине, що ви втрачаєте, пишучи форму самі: пастка, яка ловить ботів. Виносьте її за межі екрана, а не display:none, і лишайте порожньою — усе, що її заповнює, відкидається.
harvis-form
Не додавайте його. Цей атрибут — прохання до harvis написати action, а ви щойно написали його самі.

Хай надсилає браузер

Ніякого preventDefault, ніякого fetch. У відповідь приходить редирект, за яким браузер переходить сам, — саме це тримає форму робочою, коли скрипти не працюють.

Попередній рендер теж вважається JavaScript

Якщо ваша збірка записує форму в HTML, а застосунок потім перехоплює її у браузері, все одно впишіть поля — тих, що вставив harvis, немає у вашому компоненті, тож гідратація може їх викинути.

ai agents

Hand it to the agent that wrote your site

If an AI built the site, it can wire the forms up too. Copy the brief below into whatever has your project open — Claude Code, Cursor, Copilot, the chat you built the page in — and it will find the forms you already have and convert them. It covers both cases on this page, so you don't have to know which one you're in.

paste this into your ai agent
Wire the forms in this project up to harvis.dev (https://harvis.dev), which collects form submissions for static sites that have no backend. Read all of this before editing anything.

HOW IT WORKS
harvis serves every page of a site it hosts, so it can take a form post on the way past. Marking a <form> with the harvis-form attribute is the whole integration: as the page is served, harvis rewrites that tag to action="/__harvis/form/<name>" method="post", inserts a hidden honeypot field, and turns data-harvis-redirect into a hidden field. The form then posts natively, same-origin, with no JavaScript, no API key and no third-party service. Submissions appear in the site owner's dashboard (https://harvis.dev/dashboard) and are emailed to them.

STEP 1 — FIND THE FORMS
Look for every <form> in the project: .html files, and templates or components if a framework is in use. Skip search boxes and any form that posts to an API this project owns and expects a reply from. For each remaining form, decide which case it is:
- CASE A — the form is in the HTML that gets deployed: plain HTML, or a generator/framework that renders it at build time. This is the common case.
- CASE B — the form only exists once JavaScript has run: a React/Vue/Svelte/Angular component mounted in the browser, or markup a script writes. harvis rewrites the served HTML, so a form that is not in it yet is never rewritten. A form that is prerendered and then hydrated is CASE B too, because the fields harvis inserts are not in the component tree and hydration can discard them.

STEP 2A — CASE A: ADD THE ATTRIBUTE
- Add harvis-form="<name>" to the opening <form> tag. Name it for what it is — contact, signup, feedback. The name must match ^[a-z0-9][a-z0-9_-]{0,39}$ or it is collected under "default". Two forms on one site should not share a name unless they should share one list of submissions.
- Delete that form's existing action and method attributes. harvis overwrites both, so leaving them there only misleads whoever reads the file next.
- Optional: add data-harvis-redirect="/thanks.html" to choose where the visitor lands after sending. It must be a path on this same site and the file must exist in the deploy; anything pointing off-site is ignored. Without it, visitors get a plain harvis confirmation page.
- Do not add a honeypot, _harvis_hp or _harvis_redirect by hand — harvis inserts them, and a second copy is a bug.

STEP 2B — CASE B: WRITE THE ENDPOINT YOURSELF
- Set action="/__harvis/form/<name>" and method="post" on the form, and do NOT add harvis-form: that attribute is a request to rewrite, and here you have written the rewrite yourself.
- Optional redirect: a hidden input named _harvis_redirect whose value is a path on this site.
- Optional honeypot, since nothing will add one for you: an empty text input named _harvis_hp with tabindex -1, autocomplete off, aria-hidden true, positioned off-screen with position:absolute;left:-9999px rather than display:none.
- Let the browser submit it: no onSubmit handler, no preventDefault, no fetch. The reply is a 303 that the browser follows on its own, and intercepting it is what breaks the form when scripts fail.

STEP 3 — IN BOTH CASES
- Every field to be collected needs a name attribute; an input without one is never submitted. Those names become the column headings the owner reads, so prefer name, email and message over field1.
- Remove what is left of any other form service: a Formspree, Getform, Basin or FormSubmit action URL, Netlify's data-netlify attribute and its hidden form-name input, a Web3Forms access_key input, and any handler that POSTed the form somewhere else.
- Keep the client-side validation as it is. required, type="email", minlength and the rest all still work.
- File inputs are dropped: submissions are stored as text and files are not kept. If a form has one, say so rather than leaving it in silently.
- Add no script, SDK, key or config file. There is nothing to install.
- Limits, worth mentioning if a form is likely to meet one: 30 fields per submission, 5,000 characters per field, 64 KB per submission, 60 submissions per site an hour, 20 per visitor an hour, and the newest 1,000 per site are kept.

STEP 4 — DEPLOY AND REPORT
- The attribute only does anything on a served page, so deploy the site again: run npx harvis from the site folder, or tell the user to drag the folder onto https://harvis.dev/drop.
- Then tell the user which files changed, the name you gave each form, and that submissions arrive at https://harvis.dev/dashboard and by email — noting that a site deployed anonymously has no owner to email until it is claimed with the claim link.
- Suggest they send one test submission through the live site.

What it tells the agent to do

  • Find every form in the project and leave the search boxes and API calls alone.
  • Add harvis-form with a sensible name, and strip the action and method that harvis replaces anyway.
  • Write the endpoint by hand instead when the form only exists after JavaScript runs.
  • Clear out whatever the last form service left behind, and flag a file upload as something that won't be kept.
  • Redeploy, then tell you what changed and where the submissions land.

Or leave it in the repo

The same text works as a file — save it as AGENTS.md, CLAUDE.md or a project rule and an agent reads it on its own, so the next form someone adds is collected without anyone asking.

included

Що ви отримуєте

Усе нижче ввімкнено від самого початку. Сторінки налаштувань немає для жодного з цих пунктів.

  • Без JavaScript

    Форма надсилає дані так, як HTML робив це завжди. Вона працює й із заблокованими скриптами, і на повільному телефоні, і у браузері, який показує лише текст.

  • Спам відсіюється

    Кожна форма віддається з полем-приманкою, якого не бачить жодна людина, і все, що його заповнює, тихо відкидається. Обмеження частоти встановлюють межу для того, скільки за годину може надіслати один відвідувач і один сайт.

  • Скільки завгодно форм

    Дайте їм назви — форма зворотного зв'язку й форма реєстрації на одному сайті матимуть окремі списки, які можна фільтрувати й експортувати нарізно.

  • Власна сторінка подяки

    Спрямуйте форму на сторінку, яку ви написали самі, і саме туди люди потраплять після надсилання. Якщо не вказати її, вони побачать просту сторінку підтвердження.

  • Експорт коли завгодно

    Одна кнопка дає CSV зі стовпчиком для кожного поля, яке будь-хто коли-небудь надсилав, тож форма, до якої на півдорозі додалося запитання, все одно відкриється як одна таблиця.

  • Ніхто ні за ким не стежить

    Жодного скрипта відстеження, жодних куків, жодних третіх сторін усередині сторінки. Адреса відвідувача хешується перед збереженням — і лише для того, щоб обмеження частоти могло відрізнити дві відповіді.

limits

Обмеження

Щедрі для форми зворотного зв'язку й водночас достатньо тісні, щоб скрипт, наведений на ваш сайт, не завалив вашу пошту.

Полів на одну відповідь
30
Довжина одного поля
5 000 символів
Розмір однієї відповіді
64 КБ
Відповідей на сайт
60 на годину
Відповідей від відвідувача
20 на годину
Зберігається на сайт
1 000, найновіші згори
faq

Запитання

Про що питають, перш ніж поставити форму на статичний сайт.

Що таке статична форма?

Це форма на сайті, який не має власного сервера. Зазвичай це означає, що формі нікуди надсилати дані, — саме тому статичні сайти найчастіше позичають сторонній сервіс форм. harvis і так віддає кожну сторінку вашого сайту, тож може прийняти відповідь просто дорогою.

Чи треба вміти програмувати?

Треба вміти додати одне слово до рядка HTML. Якщо ваш сайт написав ШІ, попросіть його додати атрибут harvis-form до форми — він знає, як це зробити, бо саме так написано в інструкціях, які harvis публікує для ШІ-асистентів.

Чи працює це з вимкненим JavaScript?

Так. Власне, заради цього все й побудовано саме так. Форма робить звичайний HTML-запит POST, а браузер потім переходить за перенаправленням — точно як форми працювали ще до появи JavaScript.

Чи можу я й далі користуватися власним ендпоїнтом або іншим сервісом форм?

Так — просто не додавайте атрибут. Форми без harvis-form віддаються рівно такими, якими ви їх написали, разом з action. У формі, де атрибут є, harvis замінює action, бо додати атрибут — це і є спосіб сказати, куди має піти відповідь.

Це працює з React, Vue чи Svelte?

Так, з одним додатковим кроком. Якщо форма є в HTML, який видає ваша збірка, вистачить атрибута. Якщо вона з'являється лише після запуску JavaScript, впишіть у компонент action="/__harvis/form/contact" і method="post" — той самий ендпоїнт, той самий дашборд, і надсилає так само браузер.

Чи можна прикріплювати файли?

Поки що ні. Поле для файлу у формі, з якої збираються відповіді, для відвідувача працює, але сам файл не зберігається — залишаються лише текстові поля.

Що станеться з відповідями, якщо я видалю сайт?

Вони зникнуть разом із ним. Відповіді належать сайту, а не окремому розгортанню, тож повторне розгортання їх зберігає, а видалення сайту прибирає їх назавжди. Спершу експортуйте CSV, якщо хочете їх зберегти.

Опублікуйте сайт і спробуйте

Публікація безкоштовна й займає близько двох секунд. Додайте атрибут до форми, розгорніть сайт ще раз і надішліть собі тестове повідомлення.

Опублікувати сайт