> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kombo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced Mappings

> Use a TypeScript formula to change data from the connected system into the format your product needs.

<Note>
  Formulas are available on request. Contact [Kombo support](/support) to enable
  them for your environment.
</Note>

## Why use an advanced mapping?

[Custom fields](./custom-fields) give you one stable key across integrations. You might map **T-Shirt Size** from one connected system and **Workwear size** from another to `t_shirt_size`. Your application always reads `custom_fields.t_shirt_size`.

Sometimes this 1:1 mapping isn't enough. One connected system might store the size `L`, while another only stores a height in centimetres, such as `178`.

With an advanced mapping, a short TypeScript formula transforms the source value before Kombo writes it to the custom field:

```typescript theme={null}
function transform({ data }: FormulaInput): FormulaResult {
  const heightCm = data.remote['/employee']?.height_cm

  if (heightCm == null) return null
  if (heightCm < 165) return 'S'
  if (heightCm < 175) return 'M'
  if (heightCm < 185) return 'L'
  return 'XL'
}
```

A height of `178` becomes `L` under `custom_fields.t_shirt_size`. Integrations that already store `L` keep a direct mapping.

Other common uses include:

* combine `first_name` and `last_name` into one display name
* split a single `30000 EUR` field into an amount and a currency
* calculate an FTE from weekly contract hours
* translate values into your own naming convention, for example turn `Vollzeit`, `full time`, or `FT` into the same `full_time` value
* read a value that sits inside a nested response, especially useful for systems like Workday or SuccessFactors

An advanced mapping calculates one custom field. It never changes Kombo's standard unified fields.

## How advanced mappings work

Formulas are configured for a specific integration. They run when Kombo processes mapped custom fields during a [sync](../guides/sync), including records written from an incoming [webhook](../guides/webhooks). Records created by write actions, such as creating a candidate, get the formula value on the next sync.

The model must have `custom_fields` in scope, and the connector must support custom fields for that model. Formulas run after [field remapping](./remapping/introduction).

### Input and result

Every formula receives a `FormulaInput` and must return a `FormulaResult`. The editor injects these types; you do not import them.

```typescript theme={null}
function transform({ data }: FormulaInput): FormulaResult {
  return null
}
```

| Input          | What it contains                   | Where it comes from in the editor |
| -------------- | ---------------------------------- | --------------------------------- |
| `data.unified` | Kombo fields after remapping       | The last synced record            |
| `data.remote`  | Raw data from the connected system | A live response                   |

During a sync, the formula receives the values Kombo is processing for that record. `data.remote` also works when [Remote Data](../getting-started/remote-data) storage is turned off.

Fields and paths can be missing or `null`, and records can have different shapes. Use optional chaining when reading nested values.

`data.remote` is grouped by request path, and one record can contain several paths. The input snapshot shows which paths are available for the selected record.

`data.unified` does not include `id`, `remote_id`, `changed_at`, `remote_deleted_at`, `custom_fields`, `integration_fields`, raw remote data, or relation foreign keys. Use `data.remote` for raw data from the connected system. Date fields arrive as ISO strings.

`FormulaResult` must be JSON-compatible: text, a finite number, `true` or `false`, `null`, an object, or an array. A top-level `undefined` is stored as `null`; a top-level function is rejected.

TypeScript types help you in the editor only. Kombo strips them before running the formula and does not type-check it on the server, so a formula with the wrong return type can still be saved.

## Create an advanced mapping

### Create the target custom field

First, [create the Kombo custom field](./custom-fields#setting-up-custom-fields-in-kombo) that should contain the transformed value.

For example, if your product expects one formatted location for every job, create a job custom field with the key `formatted_location`. The rest of this walkthrough uses that field.

Make sure `custom_fields` is enabled for the relevant model in the integration's [scope configuration](./scopes). Run a sync so Kombo can discover fields and records you can use to preview the formula. The mapping control stays disabled until a sync discovers fields for that model.

### Open the formula editor

Open the integration in the Kombo dashboard and go to **Custom Field Mappings**. Find the target custom field and open its mapping dropdown.

There is no **Formula** option in the field list. Use the banner button instead:

* **Formula**, when the Custom Field Explorer is available for this integration
* **Open Formula Editor**, when it is not

Only users who can administrate the environment can create or edit formulas.

<Frame>
  <img
    src="https://mintcdn.com/kombo/OkHiwPlKQ9lmtUhO/images/advanced-mappings/open-formula-editor.png?fit=max&auto=format&n=OkHiwPlKQ9lmtUhO&q=85&s=1bc3e5fb7a5e1dc965c761006f028085"
    alt="Formula button in a custom field mapping
dropdown"
    width="2880"
    height="2000"
    data-path="images/advanced-mappings/open-formula-editor.png"
  />
</Frame>

### Select an example record

Nothing is preselected. Choose an example record at the top of the formula editor. Each choice is audit-logged, and the editor needs at least one already synced record.

Kombo then shows an **Input snapshot** with the data available to the formula. Use it to inspect `data.unified` and the paths under `data.remote`. They differ between connected systems.

<Frame>
  <img
    src="https://mintcdn.com/kombo/sTHM8zmKhuvL02fT/images/advanced-mappings/select-example-record.png?fit=max&auto=format&n=sTHM8zmKhuvL02fT&q=85&s=a89b83775f4e6cb541ccb96a5d08310f"
    alt="Formula editor with an example record selected and its input
snapshot"
    width="2880"
    height="2000"
    data-path="images/advanced-mappings/select-example-record.png"
  />
</Frame>

### Write and preview the formula

The entry point must be `function transform`. `const transform = () => { … }` is refused.

<Warning>
  Do not write `async function transform`. An async function returns a Promise,
  which Kombo stores as `{}` with no error.
</Warning>

Formulas cannot use `console`, `require`, `import`, or `fetch`. The preview runs automatically about 500ms after you stop typing.

The editor suggests the available fields while you type. For example, this formula reads a nested address from the connected system and formats it as one value:

```typescript theme={null}
function transform({ data }: FormulaInput): FormulaResult {
  const address = data.remote['/jobs']?.location

  if (!address) return null

  return [address.street_1, address.city, address.country]
    .filter(Boolean)
    .join(', ')
}
```

Return `null` when the source record does not contain a value.

The **Use formula** button becomes available once the current formula evaluates successfully, including when it returns `null`. Before using it, select a few representative records to check how the formula handles empty fields and different values.

A preview can succeed and **Save changes** can still refuse the mapping. Saving checks that this connector supports `custom_fields` for the model; preview does not.

### Save the mapping

Click **Use formula** to return to the custom field mapping page, then click **Save changes**.

Kombo schedules a refresh sync after the mapping changes. Once the sync finishes, the formula result appears under the custom field's key in the Unified API:

```json {5} theme={null}
{
  "id": "ABDhovHrawy5bnP6dpVLH7ow",
  "name": "Data Scientist",
  "custom_fields": {
    "formatted_location": "Hackescher Markt 1, Berlin, Deutschland"
  }
}
```

## Common transformations

### Normalize a value

You can turn a value from the connected system into the vocabulary your product uses. For example, this formula groups weekly working hours into two values:

```typescript theme={null}
function transform({ data }: FormulaInput): FormulaResult {
  const hours = data.unified.weekly_hours

  if (hours == null) return null

  return hours >= 35 ? 'full_time' : 'part_time'
}
```

### Use a fallback

Use the first available value when customers store the same information in different places:

```typescript theme={null}
function transform({ data }: FormulaInput): FormulaResult {
  return data.unified.post_url ?? data.unified.remote_url ?? null
}
```

### Read a nested value

Use `data.remote` when the value is available in the connected system but not in Kombo's unified model. The path and field names depend on the connected system and are shown in the input snapshot.

```typescript theme={null}
function transform({ data }: FormulaInput): FormulaResult {
  return data.remote['/jobs']?.location?.zip_code ?? null
}
```

## Limits

| Limit            | Value              |
| ---------------- | ------------------ |
| Formula source   | 10,000 characters  |
| Serialized input | 512,000 characters |
| Result           | 10,000 characters  |
| CPU time per run | 15 ms              |
| Memory per run   | 8 MiB              |

Formulas should perform small, deterministic transformations. They cannot call external APIs or use the current date or random values.

## If a formula fails

If a formula throws or returns an invalid value for a record, Kombo skips writing that record. Previously stored values stay as they were; the custom field is not set to `null`. Other records in the resource still process.

If more than 5% of a resource's records fail, the sync is marked `FAILED`. A formula that fails for every record will fail the sync.

On a full or default sync, formula errors also skip [deletion tracking](./deletion-policy) for affected data. Kombo will not mark missing records as deleted until a later successful sync.

## Debug a formula

If a formula fails during a sync, open [Logs](./logs). The customer-facing entry is a resource-level parsing error: `Parsing the resource "…" failed`. It does not include the formula text, the record data, or the detailed error.

<CardGroup cols={2}>
  <Card title="Custom Fields" icon="square-plus" href="./custom-fields">
    Create the target field and learn how mappings work.
  </Card>

  <Card title="Logs" icon="scroll" href="./logs">
    Investigate a formula that failed during a sync.
  </Card>
</CardGroup>
