> For the complete documentation index, see [llms.txt](https://help.ringtonic.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.ringtonic.app/guides/form-submissions.md).

# Form Submissions

Capture form submissions from your website (or your client's website) as leads in Ring Tonic — without changing the website's own form code. The same tracking script you already install for [Campaigns](/guides/campaigns.md) sends each submission back to Ring Tonic, matches it to a [Contact](/guides/contacts.md), and moves it into the **Form Submitted** stage of your pipeline.

{% hint style="info" %}
Form Submissions is available on the **Agency plan** only. Phone Calls and Form Attribution remain available on every plan.
{% endhint %}

***

### Why Form Submissions vs. Form Attribution?

Both features live on the same campaign and use the same script, but they do opposite things:

| Feature              | Direction                       | What it does                                                                                                                                                               | Plan      |
| -------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| **Form Attribution** | Ring Tonic → the website's form | Adds hidden tracking details (like the Google click ID and UTM tags) into the website's existing forms, so the attribution travels with the lead into the client's own CRM | All plans |
| **Form Submissions** | The website's form → Ring Tonic | Sends a copy of the submission to Ring Tonic the moment the visitor clicks Submit — even if the website's own form fails                                                   | Agency    |

You can enable either, both, or neither on a campaign. They are independent.

{% hint style="success" %}
**Common combo:** enable both. Form Attribution gives the client's existing CRM the marketing data it needs; Form Submissions gives Ring Tonic a guaranteed lead record even when the website's own form fails.
{% endhint %}

***

### Enabling Form Submissions on a Campaign

1. Open the campaign at **Campaigns** → your campaign → **Edit**
2. In **What would you like to track?**, check **Form Submissions**
3. The configuration card appears below — fill in:
   * **Honeypot field name** *(optional)* — see [Anti-Spam](#anti-spam) below
   * **Field mapping** — see [Field Mapping](#field-mapping) below
   * **Origin allowlist override** — see [Origin Allowlist](#origin-allowlist) below
4. Make sure at least one domain is set under **Security** → **Allowed domains** (Form Submissions requires it)
5. Click **Update Campaign**

<figure><img src="/files/ekDGuYqTz9S3F0UPLpOv" alt=""><figcaption><p>Form Submissions configuration card on a campaign's edit page</p></figcaption></figure>

***

### Field Mapping

Field mapping tells Ring Tonic where each field on the website's form should land on the contact. For every field you want to capture, you fill in two things: which **form field** to read, and which Ring Tonic **destination** it goes to.

**Destinations you can use:**

| Destination (type this) | What it captures                                                         |
| ----------------------- | ------------------------------------------------------------------------ |
| `name`                  | The contact's name                                                       |
| `email`                 | The contact's email                                                      |
| `phone`                 | The contact's phone — tidied into a standard format automatically        |
| `company`               | The contact's company                                                    |
| `value`                 | A deal value, e.g. an order total                                        |
| `custom:your_field_key` | Any of your [workspace custom fields](/guides/contacts.md#custom-fields) |

Custom field values are checked against the field's type — text is trimmed, numbers are parsed, and dropdowns must match one of the allowed options.

**Pointing at a form field:** in most cases, just enter the field's **name** — for example, `email` or `phone`. Not sure what it is? Ask whoever built the website, or check the form. Advanced users can also enter a CSS selector like `input[name="email"]` or `#email-input`.

{% hint style="info" %}
**Phone numbers are tidied automatically.** Whatever the visitor types — `(206) 739-4938`, `206.739.4938`, `+1 206 739 4938` — Ring Tonic converts it to a standard international format (`+12067394938`) based on your workspace's default country. If a submission has only an email and no phone, it's saved for your records but doesn't create a contact yet.
{% endhint %}

***

### Anti-Spam

Form Submissions runs three layers of bot defense — none of which require CAPTCHAs or visible challenges for real visitors.

#### Honeypot field

A hidden field that real people never fill in but bots usually do. Set a **Honeypot field name** (for example, `rt_website`) and have a matching hidden field added to the form:

```html
<input type="text" name="rt_website" tabindex="-1" autocomplete="off"
       style="position:absolute; left:-9999px">
```

{% hint style="info" %}
That snippet is a small piece of code for whoever maintains the website to add — you don't need to understand it. Once it's in place, any submission that fills in the hidden field is silently ignored. Recommended.
{% endhint %}

#### Bot detection

Ring Tonic automatically spots common bot and scraper signatures. Suspected bots are logged for your records but don't create a contact or trigger any automations. On by default; you can turn it off per campaign (see [Troubleshooting](#troubleshooting)).

#### Signed sessions

Every submission carries a short-lived, tamper-proof token that Ring Tonic issues when the page loads. This stops anyone from faking submissions or forging tracking data from outside the page. It's fully automatic — there's nothing for you to set up.

***

### Origin Allowlist

By default, Form Submissions only accepts submissions coming from the domains listed under the campaign's **Security** → **Allowed domains** (the same list that controls where your tracking script runs).

To narrow this further — for example, "run the tracking script everywhere, but only accept form submissions from `forms.acme.com`" — fill in **Origin allowlist override**. When it's not empty, it replaces the allowed-domains list for form submissions only.

{% hint style="warning" %}
Enter **just the domain** — no `https://` and no port number. A leading `www.` is treated the same as without it, so `www.acme.com` and `acme.com` count as the same domain.

* ✅ `acme.com`
* ❌ `https://acme.com`
  {% endhint %}

***

### What Happens When Someone Submits a Form

When a visitor submits a form on your site, Ring Tonic captures a copy of what they typed and saves it as a lead — the instant they click **Submit**, before the website's own form even finishes processing. So you still get the lead even if the website's form has a glitch.

<details>

<summary>Under the hood (for developers)</summary>

1. **On page load**, the tracking script requests a session that includes a short-lived, signed capture token — kept in memory only, never written to `localStorage`, `sessionStorage`, or cookies.
2. **On submit**, the script listens in the capture phase (before the website's own handler), collects the mapped fields, and sends a JSON beacon via `navigator.sendBeacon` (falling back to a keepalive `fetch`) to `POST /api/v1/campaigns/{uuid}/form-submissions`.
3. **The server validates** the HMAC signature, origin, plan, capture flag, honeypot, and bot signals — then writes the submission, creates or updates the contact, and fires the `form.submitted` and `contact.stage_changed` webhooks.
4. **On reload**, the cached session is reused and the token is silently re-issued; any submissions made before it resolves are queued and retried.

</details>

***

### Where the Data Goes

Once a submission lands successfully:

1. It's saved as a submission record, with the captured fields and attribution
2. A new or updated **Contact** appears in **Contacts** → the [Kanban](/guides/contacts.md#kanban-view)
3. The contact moves to the **Form Submitted** stage (first submission only — later submissions add a timeline entry but don't move the stage again)
4. The `form.submitted` webhook fires, if you've set one up (see [Webhooks](/guides/webhooks.md))
5. If you've connected Google Ads for this campaign, the submission is queued as an Enhanced Conversions upload

<figure><img src="/files/li5jfx9WSPUiQU2ZBkNs" alt="" width="375"><figcaption><p>A captured submission landing as a Contact in the Form Submitted stage</p></figcaption></figure>

***

### Troubleshooting

<details>

<summary>A form was submitted, but no lead shows up in Contacts</summary>

Start with these quick checks — no technical tools needed:

1. On the campaign's **Edit** page, confirm **Form Submissions** is still checked and you clicked **Update Campaign**.
2. Confirm the website's domain is listed under **Security** → **Allowed domains** (or in your Origin allowlist override).
3. Make sure you mapped at least the **Name**, **Email**, or **Phone** field.
4. If you just changed any of these settings, reload the website page and try again — the tracking script can take up to 30 minutes to pick up changes.
5. Make sure you're on the **Agency plan** (Form Submissions is Agency-only).

**Still stuck?** Hand this to a developer: open the browser's Network tab, find the request to `…/form-submissions`, and check its response code.

* **201** — it worked; refresh **Contacts** and check the **Form Submitted** column.
* **401** (session token mismatch) — clear the cached session and reload. In the DevTools console, run:

  ```js
  Object.keys(localStorage).filter(k => k.startsWith('_ct_session_')).forEach(k => localStorage.removeItem(k));
  location.reload();
  ```
* **403 `form_capture_not_enabled_for_workspace_plan`** — the workspace isn't on the Agency plan.
* **403 `form_capture_disabled`** — the feature was turned off between page load and submit.
* **403 `origin_not_allowed`** — the page's domain isn't on the allowed list.

</details>

<details>

<summary>I see a 403 error on a domain I just added</summary>

The tracking script remembers your settings for up to 30 minutes. Either wait for that to expire, or reload the page with `?ct_debug=true` added to the URL to force an immediate refresh.

</details>

<details>

<summary>Phone numbers aren't being tidied into a standard format</summary>

Phone formatting is based on your workspace's default country. Set the right country at **Settings** → **Workspace** → **Basic**. If a number can't be matched to that country, Ring Tonic keeps it exactly as typed and won't use it to match up duplicate contacts.

</details>

<details>

<summary>The Contact moved to "Form Submitted" but later went to "Qualified" — why?</summary>

That's the call qualification flow doing its job. A later qualified phone call automatically advances the contact's stage. The original form submission stays in the contact's timeline as history.

</details>

<details>

<summary>Some legitimate submissions are being marked as spam</summary>

Bot detection uses browser signals to spot automated traffic. If you have a legitimate case that looks automated (for example, a kiosk), turn it off on the campaign at **Edit** → **Bot Detection**.

</details>

***

### Related Guides

* [Campaigns](/guides/campaigns.md) — set up a Website Tracker campaign in the first place
* [Contacts](/guides/contacts.md) — the pipeline view where captured submissions land
* [Webhooks](/guides/webhooks.md) — subscribe to `form.submitted` events
* [API](/guides/crm-api.md) — push form-submitted events from external systems instead of using the tracking script


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.ringtonic.app/guides/form-submissions.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
