Backend olmadan çalışan formlar
Statik sitendeki bir forma tek bir öznitelik ekle, her gönderim panona düşsün. JavaScript yok, gömülü widget yok, üçüncü taraf servis yok; formu dolduran kişinin de kaydolacağı hiçbir şey yok.
Its markup, styles and deploy script are on GitHub — copy it, change the fields, redeploy.
<form harvis-form="contact"> <input name="email" type="email" required> <textarea name="message"></textarea> <button>Send</button> </form>
Üç adım, biri de yeniden deploy etmek
Öğrenilecek bir form oluşturucu ve kopyalanacak bir endpoint yok. Öznitelik, kurulumun tamamı.
- 01
Özniteliği ekle
HTML'indeki herhangi bir forma harvis-form yaz. Sitede birden fazla form varsa ona bir ad ver. action ve method'u boş bırak — sayfa sunulurken bunlar doldurulur.
- 02
Yeniden deploy et
Klasörü bir kez daha sürükle ya da npx harvis çalıştır. Yapılandırılacak bir şey, yapıştırılacak bir anahtar, panoda önce açılması gereken bir düğme yok.
- 03
Geleni oku
Gönderimler panoda sitenin altında, en yenisi üstte görünür. Tamamını okumak için bir satırı aç ya da hepsini CSV olarak al.
Bütün mesele iki öznitelik
harvis formu sunucudan çıkarken yeniden yazar, böylece yazdığın sayfa yazdığın sayfa olarak kalır.
<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>İki öznitelik
- harvis-form
- Formu toplanacak formlardan biri olarak işaretler. Değeri ona bir ad verir, böylece bir sitedeki birden fazla form birbirine karışmaz; değeri boş bırakırsan “default” altında toplanır.
- data-harvis-redirect
- İsteğe bağlı. Gönderdikten sonra insanların yönlendirileceği, sitendeki sayfa. Sitenin dışını gösteren her şey yok sayılır.
Formu JavaScript kuruyorsa, endpoint'i sen yaz
harvis, sayfa sunucudan çıkarken action'ı doldurur. Ancak bundle'ın çalıştıktan sonra var olan bir form sayfada henüz yoktur, yani doldurulacak bir şey de yoktur — yeniden yazmanın yazacağı şeyi sen yazarsın. Bu hâlâ sıradan bir HTML post'udur ve bu sayfadaki her şey yine geçerlidir.
- React
- Vue
- Svelte
- Angular
<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'in yazacağı endpoint, artı post. Son parça formun adıdır — küçük harfler, rakamlar ve tireler; bunun dışındaki her şey “default” altında toplanır.
- _harvis_redirect
- İsteğe bağlı; data-harvis-redirect'in elle yazılmış hâli. Kendi sitendeki bir yol olmalı, dışarıyı gösteren her şey yok sayılır.
- _harvis_hp
- İsteğe bağlı ve formu kendin yazınca kaybettiğin tek şey: botları yakalayan yem alan. display:none yerine ekran dışında tut ve boş bırak — onu dolduran her gönderi elenir.
- harvis-form
- Hiç koyma. Bu öznitelik, harvis'ten action'ı yazmasını istemektir; sen de onu az önce kendin yazdın.
Göndermeyi tarayıcıya bırak
preventDefault yok, fetch yok. Yanıt, tarayıcının kendiliğinden izlediği bir yönlendirmedir; formu betikler çalışmadığında da ayakta tutan şey budur.
Ön render de JavaScript sayılır
Build'in formu HTML'e yazıyor ve uygulaman sonra tarayıcıda devralıyorsa, alanları yine de yaz — harvis'in eklediği alanlar senin bileşeninde yok, dolayısıyla hydration onları atabilir.
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.
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.
Neler elde ediyorsun
Aşağıdakilerin hepsi varsayılan olarak açık. Hiçbirinin ayarlar sayfası yok.
JavaScript yok
Form, HTML'in en başından beri gönderdiği gibi gönderir. Betikler engelliyken, yavaş bir telefonda ve yalnızca metin gösteren bir tarayıcıda da çalışır.
Spam süzülür
Her form, hiçbir insanın göremediği bir yem alanla birlikte sunulur; onu dolduran her şey haber verilmeden çöpe atılır. Hız sınırları, bir ziyaretçinin ve bir sitenin bir saatte ne kadar gönderebileceğini sınırlar.
İstediğin kadar form
Onlara ad ver — aynı sitedeki iletişim formu ile kayıt formu ayrı listeler tutar, ayrı ayrı filtreleyip dışa aktarabilirsin.
Kendi teşekkür sayfan
Formu kendi yazdığın bir sayfaya yönlendir, insanlar gönderdikten sonra oraya düşsün. Belirtmezsen sade bir onay sayfası görürler.
İstediğin zaman dışa aktar
Tek bir düğme, bugüne dek gönderilmiş her alan için bir sütunu olan bir CSV verir; yani yolun ortasında bir soru eklenmiş bir form bile tek bir tablo olarak açılır.
Kimsenin peşine düşen bir şey yok
İzleme betiği yok, çerez yok, sayfada üçüncü taraf yok. Ziyaretçinin adresi saklanmadan önce hash'lenir; o da yalnızca hız sınırı iki gönderimi birbirinden ayırabilsin diye.
Sınırlar
Bir iletişim formu için cömert, sitene doğrultulmuş bir betiğin gelen kutunu doldurmasına izin vermeyecek kadar da dar.
- Gönderim başına alan
- 30
- Bir alanın uzunluğu
- 5.000 karakter
- Bir gönderimin boyutu
- 64 KB
- Site başına gönderim
- saatte 60
- Ziyaretçi başına gönderim
- saatte 20
- Site başına saklanan
- 1.000, en yenisi üstte
Sorular
Statik bir siteye form koymadan önce insanların sorduğu şeyler.
Statik form nedir?
Kendi sunucusu olmayan bir sitedeki form. Normalde bu, formun bir şeyi gönderecek yeri olmaması demektir; statik siteler de bu yüzden genellikle üçüncü taraf bir form servisi ödünç alır. harvis sitenin zaten her sayfasını sunuyor, dolayısıyla gönderimi geçerken alabilir.
Kod yazmayı bilmem gerekir mi?
Bir satır HTML'e tek bir kelime ekleyebilmen yeterli. Siteni bir yapay zekâ yazdıysa, forma harvis-form özniteliğini eklemesini iste — nasıl yapılacağını biliyor, çünkü harvis'in yapay zekâ asistanları için yayımladığı yönergelerde bu yazıyor.
JavaScript kapalıyken çalışır mı?
Çalışır. Zaten böyle kurgulanmasının sebebi bu. Form sıradan bir HTML post'u yapar, tarayıcı da ardından bir yönlendirmeyi izler; tıpkı JavaScript var olmadan önce formların çalıştığı gibi.
Kendi endpoint'imi ya da başka bir form servisini kullanmayı sürdürebilir miyim?
Evet — özniteliği eklemesen yeter. harvis-form içermeyen formlar, action'ı dahil, tam yazdığın gibi sunulur. Özniteliği taşıyan bir formda ise harvis action'ı değiştirir, çünkü özniteliği eklemek gönderimin nereye gitmesi gerektiğini söyleme biçimindir.
React, Vue veya Svelte ile çalışıyor mu?
Evet, bir adım fazlasıyla. Form, build'inin ürettiği HTML'in içindeyse öznitelik yeter. Yalnızca JavaScript çalıştıktan sonra beliriyorsa, bunun yerine bileşene action="/__harvis/form/contact" ve method="post" yaz — aynı endpoint, aynı pano, gönderme işini yine tarayıcı yapar.
İnsanlar dosya ekleyebilir mi?
Henüz değil. Toplanan bir formdaki dosya alanı ziyaretçi için hâlâ çalışır, ama dosya saklanmaz — yalnızca metin alanları tutulur.
Siteyi silersem gönderimlere ne olur?
Onlar da gider. Gönderimler bir deploy'a değil siteye aittir; yani yeniden deploy etmek onları korur, siteyi silmek ise kalıcı olarak kaldırır. Saklamak istiyorsan önce bir CSV dışa aktar.
Bir siteyi yayına al ve dene
Yayınlamak ücretsiz ve yaklaşık iki saniye sürüyor. Bir forma özniteliği ekle, yeniden deploy et ve kendine bir test mesajı gönder.