# Collect signups with forms

> Make a signup form as a hosted page, an embedded form or a popup, choose its fields, lists and consent words, and read how many visitors sign up.

Source: https://www.coritan.com/docs/organizations/commerce/email-forms/

In the dashboard:

- /dashboard/organizations/…/commerce/forms: https://www.coritan.com/dashboard/organizations

**Signup forms** makes the forms that put an address on your lists. A form collects an email address, the other details you ask for and a tick in a box that holds your consent words. It then adds the person to its lists with its tags. A form can be a page we host, a form inside your own page, or a popup. Every form counts its views and signups, so you can see how well it converts.

## Before you begin

- You need Tier 1 support or higher to read the forms and Tier 3 support or higher to make or change one.
- Make the lists the form should add people to first ([Manage your email contacts, lists and segments](/docs/organizations/commerce/email-contacts/#lists)). A form with no list adds people to your default list.
- Make the custom fields the form should ask for, such as a company or a birthday. A form can ask for `email`, **First name**, **Last name** and any custom field.
- To keep bots out, set up Cloudflare Turnstile for your account. A form asks for a challenge only when Turnstile is set up.

## Make a form

1. In the [dashboard](https://www.coritan.com/dashboard/organizations), open the organization, then **Commerce**, then **Email**, then **Signup forms**.
2. Select **New form…**.
3. Under **Details**, enter a **Name** that only you see, and choose the **Kind**.
4. Choose the **Fields**, the **Lists, tags and consent**, and the **Look and words**, as the sections below explain. The **Preview** card draws the form as a visitor sees it. Its switch shows the **Form**, the **Thanks** message and the **Confirm** message.
5. Select **Create form**.

A form needs a name and consent text before it saves. After you create it, the page shows its **Results** and its **Embed code**.

### Choose the kind

| Kind | What it is |
| --- | --- |
| In your page (`inline`) | A form that sits inside a page of your website. |
| **Popup** | A form that opens over your page after a delay, a scroll or when the visitor moves to leave. |
| Page on our domain (`page`) | A page we host, which you link to. |

Every kind also works as the hosted page, whose address is on the form's page under **Embed code**. For a popup, **Opens** chooses what shows it:

- `After a delay` takes a number of `Seconds`, from 0 to 300. It starts at 5.
- `After scrolling` takes a `Percent of the page`, from 1 to 100. It starts at 50.
- `When the visitor is about to leave` takes no number.

When a visitor sends or closes an embedded form, it stays away from that browser for 14 days.

### Choose the fields

The email field is always first and always required. Select **Add field** to add another, up to 12 fields in all. The choices are **First name**, **Last name** and each custom field of your store, marked **Custom field**. For each field you can set the label the visitor sees, a placeholder, and **Required**. Use the arrow buttons to reorder the fields below the email, and the remove button to take one out.

### Choose lists, tags and consent

**Lists a signup joins**
: The lists the form adds people to. With none ticked, a signup joins your default list.

**Tags for everyone who signs up**
: Tags added to every contact the form makes or finds, separated by commas.

**Confirmation click**
: Whether a new member confirms by *double opt-in*, an email with a link they click to join. **Follow the lists** asks when any chosen list asks. **Always ask for a confirmation click** and **Never ask** override the lists.

**Consent text**
: The words shown beside the tick box, up to 500 characters. They are kept on each contact as the proof of consent. The suggested sentence names your store and says the person can unsubscribe at any time. Select **Use the suggested sentence** to bring it back. A signup without the box ticked is refused.

**Ask visitors to pass a challenge**
: Asks for a Cloudflare Turnstile check. It is on for a new form. It has an effect only while Turnstile is set up for your account. Without a valid answer, a signup is refused.

### Choose the look and the words

Set the **Heading**, an optional **Description**, the **Button** label, the **Thank you message** and the **Message when a confirmation is needed**. To send people to a page after a signup instead of showing the message, enter its address under **Send people to a page after signup**. It must start with `https://`. Four colours set the **Background**, **Text**, **Accent** and **Button text**.

## Put the form on your site

Open the form. **Embed code** holds four things, each with a copy button:

1. The hosted address. Link to it from your site, an email or a social profile. The page shows the form in your organization's name and colours, and counts a view when it opens.
2. **Script tag**. One tag that shows the form where the tag sits, or as a popup for a popup form.
3. **Container and script**. A `div` the form fills, then the script. Use it to choose where an inline form goes.
4. **Always open as a popup**. A tag that opens the form as a popup, whatever its kind.

The script needs no other file, uses no `eval`, and sets every style through the element, so a page with a strict Content Security Policy can run it. It counts one view for each page load.

A storefront that draws its own form calls the Store API instead, as [Grow your email list](/docs/organizations/storefront/store-api/#grow-your-email-list) shows.

## What a signup does

When a visitor sends the form, we:

1. Check the fields, the consent box and the challenge. A missing consent answers that the box must be ticked, and a missing required field names the field.
2. Add the signup to the form's **Signups**.
3. Subscribe the address to the form's lists with its tags. The contact's source is `form:` and the form's number, and its consent record is the form's words. The consent method is `popup` for a popup and `form` for the others.
4. With double opt-in, hold the contact as **Pending** and email the `Confirm subscription` email. The contact joins the lists when its link is opened. The link works for 7 days.
5. When a list has a welcome email on, send it as the contact joins. A contact who joins starts every automation whose trigger is `Fills in a form` with this form, once the contact is subscribed or has confirmed ([Send emails automatically with automations](/docs/organizations/commerce/email-automations/)).

The answer is the same for an address the store knows and one it does not. An address that unsubscribed, bounced or marked an email as spam changes nothing, and the form shows its usual message. A form never tells a visitor whether the store knows an address.

A hosted or embedded signup makes a live contact when your store is live and a test contact before that. A signup posted to the Store API takes the mode of the publishable key.

## Results

**Results** shows the form's **Views**, **Signups** and **Conversion**: signups divided by views. The list of forms shows the same three figures for each form, with **Active**, **Archived** and **All** to filter. A popup with a view and no signup is worth another look: change when it opens, or the words.

## Archive or delete a form

Open the form's actions menu (**Form actions**) and choose **Delete form…** or **Archive form…**. The dialog asks you to type the form's name.

- A form with no views and no signups is removed.
- A form with views or signups is archived. Its page, script and Store API form stop working, and its numbers stay. Select **Restore form** on an archived form to turn it back on.
- A form that an automation starts on cannot be removed. Change or archive the automation first.

## The preference center and the unsubscribe page

Every marketing email carries two links that show a page we host, in your organization's name and colours:

Unsubscribe page
: Asks whether to stop marketing email from your store to the reader's address, with a button. Nothing changes until the reader presses it. Pressing it unsubscribes the contact from every list and puts the address on the suppression list. A reader who did it by mistake can tick a box that holds the sentence `I want to receive marketing emails from` and your organization's name, and subscribe again. A mail provider's one-click request unsubscribes at once.

Preference center
: Shows the address in part, such as `j***@example.com`, and the lists marked **Offer on the preference page** as boxes, with `Unsubscribe from everything`. A reader ticks the lists to get and presses `Save my choices`. Choosing lists after unsubscribing is the reader's own consent and subscribes them again. An address that bounced or marked an email as spam is told nothing can change here. A pending address is asked to open the confirmation email first. The link works for 90 days.

The `Welcome to a list` email also links to the preference center.

## Result

- The form shows on your site, or at its hosted address, and each visit adds a view.
- A signup adds a **Signups** count and a contact with the consent words and the source `form:` and the form's number.

## Troubleshooting

The form does not appear on my site
: The page may block the script, or the form is **Archived**. Check the form's status, and that your page holds the tag exactly as **Embed code** shows it.

A signup is refused and asks for the consent box
: The visitor did not tick it. A form always asks, and the answer says the box must be ticked.

A signup is refused with a challenge error
: The form asks for a Turnstile check and the visitor did not pass it. Check that Turnstile is set up for your account, or turn off **Ask visitors to pass a challenge**.

A contact stays **Pending**
: The list or the form asks for a confirmation click and the contact has not clicked. The link works for 7 days. A new signup after 10 minutes sends another.

**Views** stays at 0
: The page or script was not opened, or the storefront's own form never reports its views. Call `POST /store/marketing/forms/{public_id}/views` when the form shows.

**Create form** or **Save changes** names a field
: The message says what to fix, such as a colour that is not `#rrggbb` or a redirect that does not start with `https://`.

## Related

- [Manage your email contacts, lists and segments](/docs/organizations/commerce/email-contacts/)
- [Send emails automatically with automations](/docs/organizations/commerce/email-automations/)
- [Build a checkout with the Store API](/docs/organizations/storefront/store-api/#grow-your-email-list)
- [Collect and export your store's leads](/docs/organizations/commerce/leads/)

## With the API

The routes are under `https://api.coritan.com/api/v1/orgs/{org_slug}/marketing/forms`. Reading takes `marketing.campaigns:read` and changing takes `marketing.campaigns:write` ([API key scopes](/docs/organizations/commerce/email-marketing/#api-key-scopes)).

`GET /forms/catalog` lists what a form can use: the `kinds`, the `fields` (built in and your custom fields, with their input `type`), `max_fields`, the `popup_triggers`, the `default_design` and the `default_consent_text`.

`POST /forms` makes a form and answers `201` with `{form}`:

```bash
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/marketing/forms" \
  -H "X-API-Key: $ORG_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Footer signup", "kind": "inline", "list_ids": [3], "tag_names": ["footer"],
       "consent_text": "I agree to get emails from Acme. I can unsubscribe at any time.",
       "fields": [{"key": "email", "required": true}, {"key": "first_name", "label": "Your name"}],
       "design": {"heading": "Join our list", "button_label": "Sign me up"}}'
```

| Field | What it takes |
| --- | --- |
| `name` | Required, up to 100 characters. |
| `consent_text` | Required, up to 500 characters. |
| `kind` | `inline` (the default), `popup` or `page`. |
| `list_ids` | Lists a signup joins. Empty means the default list. Each must be yours and not archived, up to 20. |
| `tag_names` | Tags for everyone who signs up, up to 20. |
| `fields` | `[{key, label, required, placeholder}]`. The email field is added, put first and made required when missing. A key is `email`, `first_name`, `last_name` or the key of a custom field. Up to 12. |
| `double_opt_in` | `true` or `false` to override the lists, or `null` to follow them. |
| `design` | `heading`, `description`, `button_label`, `success_message`, `pending_message`, `redirect_url`, `colors` (`background`, `text`, `accent`, `button_text`, each `#rgb` or `#rrggbb`) and, for a popup, `trigger` (`{"type": "delay", "value": 5}`, `{"type": "scroll", "value": 50}` or `{"type": "exit"}`). |
| `turnstile` | `true` or `false`. `false` when left out. |

A form is `{id, public_id, name, kind, status, list_ids, tag_names, fields, consent_text, double_opt_in, design, turnstile, views, submissions, conversion_rate, hosted_url, created_at, updated_at}`. `public_id` is what a storefront and the hosted address use. `status` is `active` or `archived`.

- `GET /forms` lists forms, newest first, as `{total, limit, offset, forms}`. `status` filters by `active` or `archived`, and `kind` by `inline`, `popup` or `page`.
- `GET /forms/{form_id}` answers one form.
- `PATCH /forms/{form_id}` changes what you send. `design` is merged into the stored design key by key, and `status` is `active` or `archived`.
- `DELETE /forms/{form_id}` removes a form nobody has seen and answers `{deleted: true, id}`. A form with views or signups is archived and answers `{deleted: false, archived: true, id}`. It answers `409` with `form_in_use` while an automation starts on it.
- `GET /forms/{form_id}/embed` answers `{hosted_url, script, html, popup_script}`, the four pieces of code under **Embed code**.

A refused setting answers `422` with `invalid` and a `field` that names it, such as `design.colors.accent` or `fields[1].key`.

## API

- `GET /api/v1/orgs/{org_slug}/marketing/forms`: Your signup forms, newest first, with their views, signups and conversion rate (https://www.coritan.com/docs/api/reference/organizations/marketing/marketing/#op-get-api-v1-orgs-org-slug-marketing-forms)
- `POST /api/v1/orgs/{org_slug}/marketing/forms`: Make a signup form (https://www.coritan.com/docs/api/reference/organizations/marketing/marketing/#op-post-api-v1-orgs-org-slug-marketing-forms)
- `GET /api/v1/orgs/{org_slug}/marketing/forms/catalog`: Form catalog (https://www.coritan.com/docs/api/reference/organizations/marketing/marketing/#op-get-api-v1-orgs-org-slug-marketing-forms-catalog)
- `GET /api/v1/orgs/{org_slug}/marketing/forms/{form_id}`: One form with its settings, views and signups (https://www.coritan.com/docs/api/reference/organizations/marketing/marketing/#op-get-api-v1-orgs-org-slug-marketing-forms-form-id)
- `PATCH /api/v1/orgs/{org_slug}/marketing/forms/{form_id}`: Change a form (https://www.coritan.com/docs/api/reference/organizations/marketing/marketing/#op-patch-api-v1-orgs-org-slug-marketing-forms-form-id)
- `DELETE /api/v1/orgs/{org_slug}/marketing/forms/{form_id}`: Delete a form nobody has seen: {deleted: true} (https://www.coritan.com/docs/api/reference/organizations/marketing/marketing/#op-delete-api-v1-orgs-org-slug-marketing-forms-form-id)
- `GET /api/v1/orgs/{org_slug}/marketing/forms/{form_id}/embed`: Form embed (https://www.coritan.com/docs/api/reference/organizations/marketing/marketing/#op-get-api-v1-orgs-org-slug-marketing-forms-form-id-embed)
