# Field validation

Field validation ensures that the data collected in your flows meets defined formatting, business, and quality requirements. Formsort supports both built-in and custom validators.

***

### Built-in Validators

Formsort includes many default validators for common input types:

* **Number questions**: Enforce min/max value, integer constraints, and step intervals.
* **Email fields**: Automatically validate email formatting.
* **Text fields**: Can be configured with length or character restrictions.

These default validators cover the most common cases. For advanced use cases, **custom validators** are available.

***

### Custom Validators (Enterprise Only)

Custom validators allow you to define your own validation logic using regular expressions, custom code, or asynchronous API calls. They are defined at the **workspace** level and can be reused across flows.

<figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2F0UTIGdJakn1xEAQRxQ1w%2Fimage.png?alt=media&#x26;token=f07e2ac3-3921-4b1d-b78d-9908cb88075e" alt=""><figcaption><p>Custom validators are defined at the workspace level</p></figcaption></figure>

### Defining Custom Validators

Custom validators are composed of two main parts:

#### **1. Validator Metadata**

Metadata includes:

* **Name** and **description** (used for identification in the Studio)
* **Answer type** (e.g., string, number, object) – this controls which questions or variables can use the validator

<div align="left"><figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FAHYNKhv5nVZJR0fLcd45%2Fimage.png?alt=media&#x26;token=bcf84e39-c271-4a08-abbf-8b920446a6ab" alt="" width="281"><figcaption></figcaption></figure></div>

{% hint style="info" %}
Ensure the validator's answer type matches the target question’s type—e.g., string validators won't apply to number fields.
{% endhint %}

#### **2. Validation Rules**

Validators can contain multiple rules. Each rule must pass for the value to be considered valid.

<div align="left"><figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FXpa95BNl24u0mPhtJNtC%2Fimage.png?alt=media&#x26;token=49bb7121-ed4b-4012-8dad-058d0c057c83" alt="" width="275"><figcaption></figcaption></figure></div>

#### **Rule Severity**

* **Error**: Blocking. The responder cannot proceed unless the input is corrected.

<div align="left" data-full-width="false"><figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FwQiQ6Ikr3WYANrE23lh1%2Fimage.png?alt=media&#x26;token=9c45bfab-38f0-4421-a02e-db9a2a065a7d" alt="" width="375"><figcaption></figcaption></figure></div>

* **Warning**: Non-blocking. The responder is alerted, but may choose to proceed.

<div align="left"><figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FdazD1X4oeJgfRJ0tBzKm%2Fimage.png?alt=media&#x26;token=6a4e9440-aef0-4020-b973-52dd628894c2" alt="" width="375"><figcaption></figcaption></figure></div>

### Regular expression rules

Regular expressions (`regex`) are available only for string inputs. You can create rules for inputs that **must match** or **must not match** a given pattern.

**Example: Twitter Handle Validator**

| Rule Type          | Pattern           | Error Message                                                                   |
| ------------------ | ----------------- | ------------------------------------------------------------------------------- |
| **Must match**     | `^[a-zA-Z0-9_]+$` | A username can only contain alphanumeric characters (A–Z, 0–9) and underscores. |
| **Must match**     | `^.{1,15}$`       | Handles must be between 1 and 15 characters long.                               |
| **Must not match** | \`Twitter         | Admin\` (case-insensitive)                                                      |

{% hint style="info" %}
Rules 1 and 2 (and probably 3) can be collapsed into a single regular expression that checks for both, which would be  `^[a-zA-Z0-9_]{1,15}$.`

Splitting out rules is preferred, as it allows for more targeted error messages. We can warn users with a specific message when they have an invalid character OR their handle is too long, making it easier to see what's wrong with the input and correct it.
{% endhint %}

<div align="left"><figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FT0ddEufueRuJSSuKugmH%2Fimage.png?alt=media&#x26;token=bba9bc3d-2910-4ef5-8dc5-605c66a3de2c" alt=""><figcaption></figcaption></figure></div>

### Custom code rules

For more flexibility, you can write custom validation functions using TypeScript.

**Example:**

```typescript
function myFunction(value: string): ValidatorResult | undefined { // readonly line
  if (value.match(/admin|twitter/i)) {
    return {
      severity: 'error',
      message: 'Handle cannot contain the words "admin" or "twitter"'
    }
  }
  if (value.match(/[^a-zA-Z0-9_]/)) {
    return {
      severity: 'error',
      message: 'A username can only contain alphanumeric characters (letters A-Z, numbers 0-9) with the exception of underscores.'
    }
  }
  if (value.length > 15) {
    return {
      severity: 'error',
      message: 'Usernames cannot be more than 15 characters long'
    }
  }
}
```

<figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2Ftfmt67njdkm4P7hwnk2m%2Fimage.png?alt=media&#x26;token=803ef911-5235-42d7-a1d4-3e1845a4863f" alt=""><figcaption><p>Writing a custom code validator</p></figcaption></figure>

* Return a `ValidatorResult` when the input is invalid.
* Return `undefined` when input passes validation.

{% hint style="info" %}
Note: Only the first validation error is shown—custom functions exit at the first `return`.
{% endhint %}

### Async custom code

Enable **async** mode to fetch data from external sources during validation using `await`.

**Example (hypothetical Twitter handle check):**

```typescript
function myFunction(value: string): Promise<ValidatorResult | undefined> { // readonly line
  const res = await fetch('https://api.twitter.com/check-handle');
  const handleInfo = await res.json();
  if (handleInfo.taken) {
    return {
      severity: 'error',
      message: 'This handle has already been registered'
    }
  }
}
```

{% hint style="info" %}
You must enable the **Async** checkbox in the validator configuration.
{% endhint %}

### Testing validators

Use the **Test** tab to try out inputs and preview validation behavior:

* **Regex rules**: All rules are evaluated in parallel. Violations for each rule are shown independently.
* **Custom functions**: Only the first failed check is returned.

**Examples:**

<figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2Fssjgpw6StTlFHV1mpF0W%2Fimage.png?alt=media&#x26;token=15441d98-524c-4236-a22f-fc80033e08b0" alt=""><figcaption><p>Rule 1 being enforced</p></figcaption></figure>

<figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2Fb5UuHnCei4HMjJFLYAiR%2Fimage.png?alt=media&#x26;token=ffc4f9a1-d00f-4e1f-803f-e7e87a5712cf" alt=""><figcaption><p>Rule 2 being enforced</p></figcaption></figure>

<figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FRfcjNXdHrhPgYy58EAYU%2Fimage.png?alt=media&#x26;token=2c82aa28-55ef-4ab3-8451-d8bf417a5263" alt=""><figcaption><p>Rule 3 being enforced</p></figcaption></figure>

Using the Regular Experssion UI (described [above](#regular-expression-rules)) has the added benefit of evaluating all rules concurrently, and outputting an error message for each rule that is violated:&#x20;

<figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FhFWD4uK4ct6UNXcBj6Pq%2Fimage.png?alt=media&#x26;token=bdf9249b-6198-4b57-a106-bc0321e29a03" alt=""><figcaption><p>All rules being enforced at once</p></figcaption></figure>

***

### Using custom validators in a flow

Once created, custom validators become selectable in Question settings (if the question’s data type matches the validator).

<figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FtfiFbhvrYd8MHNYwSoa1%2Fimage.png?alt=media&#x26;token=94dc2b1b-ae3b-4281-b7b3-c7be841f77b4" alt=""><figcaption><p>Picking a validator within the content editor</p></figcaption></figure>

***

### Updating custom validators

You can modify validators at any time. However:

* **Flows using the validator need to be redeployed to pick up changes.**
* Use the **Show usages** option to view which flows depend on a validator.

<figure><img src="https://1036686854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJPnL__mOdr_mLZ8nwf%2Fuploads%2FGCUfNa2dmbtTxuZ9ZJet%2Fimage.png?alt=media&#x26;token=58802690-8d24-47f7-92f1-a2f395ffe376" alt=""><figcaption></figcaption></figure>

### Deleting Validators

Custom validators can be deleted from the validator list.

* **Flows already using the validator will continue to function.**
* Deleted validators will no longer be available to assign to new questions or answers.
