# Zapier Filters, Paths, Formatter and Code by Zapier in n8n

> Source: https://workflowexit.com/zapier-paths-formatter-code-to-n8n · Updated 2026-10-17

Zapier's built-in apps all have an n8n counterpart, but several behave a little differently. Filter becomes an **If** node. Each Paths branch becomes its own **If**, because every matching path runs in Zapier. Formatter becomes an expression in **Edit Fields**. Code by Zapier becomes a **Code** node with a different input and return shape. Storage, Delay and Webhooks map to static data, **Wait** and **Webhook** or **HTTP Request**.

This guide shows each mapping with a small n8n example. To get the Zap definitions first, see [how to export your Zaps](/export-zapier-zaps). The [Zapier to n8n converter](/zapier-to-n8n) does all of the below by rule.

## The mapping at a glance

| Zapier | n8n | Watch out for |
|---|---|---|
| Filter by Zapier | **If** (or **Filter**) | Zapier text rules are case-insensitive |
| Paths by Zapier | One **If** per path, or **Switch** with all matching outputs | All matching paths run, left to right |
| Formatter by Zapier | **Edit Fields (Set)** with expressions | Date tokens differ (Moment vs Luxon) |
| Code by Zapier (JavaScript) | **Code** | `inputData` and `output` don't exist |
| Code by Zapier (Python) | **Code** (JavaScript) | Python on n8n Cloud can't import modules |
| Storage by Zapier | **Code** + workflow static data, or a **Data Table** | Static data is per workflow |
| Delay by Zapier | **Wait** | Delay After Queue has no direct twin |
| Webhooks by Zapier, catch hook | **Webhook** | New URL; fields move under `body` |
| Webhooks by Zapier, request | **HTTP Request** | Match the body content type |
| Looping by Zapier | Nothing, or **Split Out** | n8n already runs each node once per item |

Field mappings change syntax everywhere. Zapier's `{{123456__email}}` points at a step by id; in n8n it becomes `{{ $('Find contact').item.json.email }}`, which points at a node by name.

## Filter by Zapier → If

A Zapier filter has rules, AND/OR groups, and stops the Zap when the rules fail. In n8n, add an **If** node and connect only the **true** output. Items that fail the rules go out of the false output, which you leave unconnected, so the run stops there.

Two details:

- **Case.** Zapier's text conditions ignore case: "Contains: urgent" matches "URGENT". In the If node, open **Options → Ignore Case** and turn it on.
- **Groups.** Zapier ANDs the rules inside a group and ORs the groups. An If node has one AND or OR for all its conditions. For mixed groups, use one boolean condition with an expression:

```javascript
{{ ($json.country === 'US' && Number($json.amount) > 100) || $json.vip === true }}
```

Set it to **Boolean → is true**. The **Filter** node works too if you just want to drop the items that fail.

## Paths by Zapier → If per path

In Zapier, **every path whose rules match runs**, one at a time from left to right ([Paths docs](https://help.zapier.com/hc/en-us/articles/8496288555917)). A fallback path runs only when no other path matched, and an "Always run" path runs every time.

A Switch node in its default mode sends each item to the first matching output only. That's not what Zapier did. Two options:

1. **One If node per path.** Connect the previous step to an If for Path A, another for Path B and so on. Each If's true output leads to that path's steps. For a fallback path, use an If whose condition is the negation of all the others. For an "Always run" path, connect its first step directly.
2. **A Switch with "Send data to all matching outputs"** turned on in its options. Shorter, but harder to read with complex rules.

Order matters when paths touch the same record. n8n runs branches one after another, starting with the topmost node on the canvas. Put Path A's nodes above Path B's to keep Zapier's left-to-right order.

## Formatter by Zapier → expressions

Most Formatter actions are one expression in an **Edit Fields (Set)** node. With the incoming field called `name`, `amount` or `date`:

| Formatter action | n8n expression |
|---|---|
| Text: Uppercase | `{{ $json.name.toUpperCase() }}` |
| Text: Capitalize | `{{ $json.name.toLowerCase().replace(/(^\|\s)\S/g, c => c.toUpperCase()) }}` |
| Text: Trim whitespace | `{{ $json.name.trim() }}` |
| Text: Extract email | `{{ ($json.text.match(/[\w.+-]+@[\w-]+(\.[\w-]+)+/) \|\| [''])[0] }}` |
| Text: Default value | `{{ $json.name?.trim() ? $json.name : 'Unknown' }}` |
| Numbers: Perform math operation | `{{ Number($json.amount) * 1.2 }}` |
| Date: Format | `{{ DateTime.fromISO($json.date).toFormat('yyyy-MM-dd') }}` |
| Date: Add/subtract time | `{{ DateTime.fromISO($json.date).plus({ days: 3 }).toISO() }}` |
| Utilities: Lookup table | `{{ ({ US: 'United States', DE: 'Germany' })[$json.country] ?? 'Other' }}` |
| Utilities: Pick from list | `{{ String($json.tags).split(',')[0].trim() }}` |

**Date tokens.** Zapier writes formats in Moment.js style; n8n expressions use Luxon. `YYYY` → `yyyy`, `DD` → `dd`, `dddd` → `cccc`, `A` → `a`. `MM`, `HH` and `mm` stay the same. A wrong token doesn't raise an error, it just prints the wrong thing, so test each date field with a real value.

**Time zones.** `DateTime.fromISO($json.date, { zone: 'Europe/Berlin' })` reads a date in a zone, and `.setZone('America/New_York')` converts it. Without a zone, n8n uses the workflow's time zone.

## Code by Zapier → Code node

Code by Zapier gives your code an `inputData` object of mapped fields (all strings), lets you call `fetch`, and takes the result from `output` or `return`. The n8n Code node reads earlier nodes directly and must return an array of items.

Zapier:

```javascript
const res = await fetch(`https://api.example.com/users?email=${inputData.email}`);
const user = await res.json();
output = { id: user.id, plan: user.plan };
```

n8n (Code node, **Run Once for All Items**):

```javascript
const email = $('Trigger').first().json.email;
const user = await this.helpers.httpRequest({
  url: `https://api.example.com/users?email=${encodeURIComponent(email)}`,
  json: true,
});
return [{ json: { id: user.id, plan: user.plan } }];
```

What changes:

- **Inputs.** Replace `inputData.x` with `$('Node name').first().json.x`, or `$json.x` in Run Once for Each Item mode.
- **Output.** Return `[{ json: {...} }]`. Returning several objects gives several items, and every later node runs once per item.
- **Packages.** On n8n Cloud the Code node can import only `crypto` and `moment`. Self-hosted n8n can allow more with `NODE_FUNCTION_ALLOW_EXTERNAL`. Zaps that had packages turned on need rewriting for Cloud.
- **Secrets.** If the Zapier code has an API key pasted in, move it to an n8n credential and make the call from an HTTP Request node that uses it.

**Python.** Code by Zapier Python uses `input_data` and `output`. n8n's Code node can run Python, but on n8n Cloud it can't import any modules, not even the standard library. Port the step to JavaScript. Our converter does this with an AI rewrite and then validates the result.

## Storage by Zapier → static data or a Data Table

Storage by Zapier is a key-value store shared across Zaps. n8n has two replacements:

- **Workflow static data**, for values one workflow keeps between runs:

```javascript
const store = $getWorkflowStaticData('global');
store.lastId = $json.id;            // Set Value
const last = store.lastId ?? null;  // Get Value
return [{ json: { last } }];
```

Static data is saved only on production runs of a published workflow, not on manual test runs, and other workflows can't read it.

- **A Data Table**, when several workflows share the values. The Data Table node inserts, updates and gets rows.

The stored values themselves are not in Zapier's export. Copy the keys you need before you switch.

## Delay by Zapier → Wait

| Zapier | n8n Wait node |
|---|---|
| Delay For (e.g. 2 hours) | Resume: **After Time Interval**, 2 hours |
| Delay Until (a date) | Resume: **At Specified Time**, with the date as an expression |
| Delay After Queue | No direct equivalent; spread the runs with a schedule or a queue in a Data Table |

## Webhooks by Zapier

**Catch Hook → Webhook node.** Add a Webhook node, set the HTTP method your sender uses, publish the workflow and give the sender the **production URL**. The test URL works only while you listen in the editor. Zapier's catch-hook URL isn't in the export and doesn't carry over.

The data moves: n8n's Webhook node outputs `headers`, `params`, `query` and `body`. A field Zapier mapped as `{{1__email}}` becomes `{{ $('Webhook').item.json.body.email }}`. For Catch Raw Hook, turn on the Webhook node's **Raw Body** option.

**POST, GET, PUT and Custom Request → HTTP Request node.** Copy the method, URL, query and headers. Then match the body: Zapier's Payload Type **form** is **Form URLencoded** in n8n, **json** is a JSON body. Leaving n8n on JSON when the API expected a form is a common reason for a 400 error. Move any keys in headers to a Header Auth credential.

## Line items and loops

n8n works on lists of items. A node that receives ten items runs ten times, once per item. Many Looping by Zapier steps therefore need no node at all. To turn one item that holds an array into many items, use **Split Out**. To send items in batches, use **Loop Over Items**.

## Testing

Run each workflow once by hand in the editor, compare its output with the matching Zap run in Zap history, then publish it and turn the Zap off. If both run at once, every email and row goes out twice.

To check whether the move pays off, see [Zapier vs n8n cost](/zapier-vs-n8n-cost). To have Filters, Paths, Formatter, Code, Storage, Delay and Webhooks converted for you, drop your export into the [free Zapier report](/zapier-to-n8n).

## Frequently asked questions

### What is the n8n equivalent of Paths by Zapier?

An If node per path, or a Switch node with "Send data to all matching outputs" turned on. In Zapier every path whose rules match runs, one after another from left to right, so a Switch that stops at the first match behaves differently.

### What replaces Formatter by Zapier in n8n?

Mostly expressions in an Edit Fields (Set) node: JavaScript string and number methods for text and numbers, Luxon for dates, and an object literal for lookup tables. Zapier's date tokens (YYYY-MM-DD) become Luxon tokens (yyyy-MM-dd).

### Will my Code by Zapier JavaScript run in n8n?

Not unchanged. Code by Zapier reads inputData and sets output; the n8n Code node reads items with $input or $('Node name') and returns an array of { json } objects. On n8n Cloud the Code node can only import crypto and moment.

### Can n8n run my Code by Zapier Python steps?

n8n's Code node supports Python, but on n8n Cloud Python can't import any modules. Porting the step to JavaScript is usually the safer route.

### Why are my webhook fields empty in n8n?

n8n's Webhook node puts the request body under body, the query string under query and headers under headers. A field Zapier showed as email is $json.body.email in n8n.
