Form in Cursor

Tell the agent not to add an API route. The form talks to Formgong directly.

  1. Open the site repo in Cursor.
  2. Paste the prompt.
  3. Confirm there is no server secret just for this form.
  4. Export CSV from the dashboard when leads arrive.

Prompt

Add a contact form to the existing site in this repo, using its current components and styles. Submissions go to Formgong, a hosted form backend. Do not create an API route, serverless function, or environment variable for this form.

Formgong spec (follow exactly):
- Plain HTML: <form action="https://formgong.com/submit" method="POST">. With JavaScript, POST the same fields to https://formgong.com/submit using fetch.
- Hidden field access_key with value fk_your_access_key. The key is public and belongs in frontend code. Do not move it to a server or a secret.
- Hidden field _lang with the page language code, e.g. "en" (on multilingual sites use document.documentElement.lang). Formgong uses it for error messages, the thank-you page, and the autoreply.
- Fields: name, email, message (required); phone is optional. Keep these field names, and use <input type="email"> for email so browsers check the address.
- Honeypot: <input type="text" name="botcheck" tabindex="-1" autocomplete="off"> inside a wrapper with aria-hidden="true", visually hidden with CSS (position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)). Never fill it.
- Success, plain form POST: optionally add a hidden _redirect field with the absolute https URL of the site's thank-you page. Without it, Formgong shows its own thank-you page.
- Success, fetch: send Accept: application/json (and Content-Type: application/json for a JSON body; for FormData let the browser set it). If the response has success === true, show an inline thank-you message and reset the form; otherwise show the response's message.
- Turnstile: only if I give you a Cloudflare Turnstile site key, add <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> and <div class="cf-turnstile" data-sitekey="SITE_KEY"></div> inside the form. Otherwise leave it out.
- Optional: add <script src="https://formgong.com/fg.js" async></script> once per page. It fills _lang from <html lang>, sets the Turnstile language, and counts form views without cookies.
- Do not create a backend, API route, server function, database table, or email-sending code (Supabase, Resend, SendGrid, nodemailer), and do not add secrets. No file uploads.

Minimal code

HTML

<form action="https://formgong.com/submit" method="POST">
  <input type="hidden" name="access_key" value="fk_your_access_key">
  <input type="hidden" name="_lang" value="en">
  <label>Name <input type="text" name="name" autocomplete="name" placeholder="Your name" required></label>
  <label>Email <input type="email" name="email" autocomplete="email" placeholder="you@example.com" required></label>
  <label>Message <textarea name="message" placeholder="How can we help?" required></textarea></label>
  <div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
  <label>Leave this field empty<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
  
  <button type="submit">Send</button>
</form>

fetch

async function onSubmit(event) {
  event.preventDefault();
  const fields = Object.fromEntries(new FormData(event.currentTarget));
  const response = await fetch("https://formgong.com/submit", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
    },
    // _lang: language of Formgong messages and the autoreply (multilingual site: document.documentElement.lang).
    body: JSON.stringify({ _lang: "en", ...fields, access_key: "fk_your_access_key" }),
  });
  const result = await response.json();
  if (!result.success) throw new Error(result.message || "Could not send. Please try again.");
  return result.message; // localized "Sent. Thank you!"
}

Add to an existing project: npx formgong init (npm: formgong)

Before you publish

  • The form posts to https://formgong.com/submit (form action or fetch URL).
  • access_key holds your key from the Formgong dashboard, not fk_your_access_key.
  • A hidden, empty botcheck field is present.
  • _lang matches the page language.
  • No API route, server function, database table, or secret was added for the form.
  • A test submission shows up in the Formgong inbox and in your email.

What Cursor tends to get wrong

In a real codebase, Cursor follows the patterns it sees. If the project has an API folder, it may add a new endpoint, an email package and an .env entry for a key. The prompt rules this out and asks for a plain POST or fetch to Formgong instead.

Cursor also follows project rules. If you add a Formgong rules file to .cursor/rules, later changes to the form keep the same endpoint, honeypot and success handling without repeating the prompt.

For agents: connect the MCP server

Cursor reads MCP servers from .cursor/mcp.json in the project, or from ~/.cursor/mcp.json for all projects. The settings below take the token from the FORMGONG_TOKEN environment variable, so the token stays out of the repository.

Cursor MCP settings

{
  "mcpServers": {
    "formgong": {
      "url": "https://formgong.com/mcp",
      "headers": {
        "Authorization": "Bearer ${env:FORMGONG_TOKEN}"
      }
    }
  }
}

Prompt for an agent with MCP

With the MCP server connected, this prompt lets the agent find your form and key on its own:

Use the Formgong MCP server to add a working contact form to this site.
1. Call list_forms. If there is no form for this site, call create_form with the site name.
2. Call get_form_snippet with that form_id and framework "react" (use "html" for a static page, "next" for the Next.js App Router).
3. Add the returned code as the contact form, styled like the rest of the site. Keep access_key, _lang and the botcheck honeypot exactly as returned.
4. Do not add a backend, API route, database or email code, and never write the fgp_ token into project files.

Check the result

  1. Read the diff: one form component or section, no new API route, no new .env entry.
  2. Run the site locally and send a test message.
  3. Deploy and run the form checker on the live page.
  4. Optional: commit .cursor/rules/formgong.mdc so later edits follow the same rules.

The form checker reads the published page and lists concrete problems, such as a missing name attribute or a placeholder key.

Questions

Is it safe to commit the access key?

Yes. The access key only lets someone send submissions to that form, which anyone can already do on your site. It can't read your inbox or change settings. Keep the API token (fgp_…) out of the repository.

Should I use the prompt or a rules file?

Use the prompt once to add the form. Add the rules file if the project keeps changing, so Cursor follows the same rules every time it touches a form.

Is the access key in the prompt a secret?

No. The access key (fk_…) is public by design. It can only send submissions to one form, which anyone can already do on your site. Secrets, such as a Turnstile secret key or a Formgong API token (fgp_…), must never go into a prompt or frontend code.

How do I put my real key into the prompt?

Copy it from your Formgong dashboard and replace fk_your_access_key. If you are signed in, use the button under the prompt. It reads your forms from your own dashboard in the browser and swaps the key in. Nothing is sent to the AI tool until you paste the prompt.

Cursor contact form →

Get a key