# Liquid Filters Hook

> Add your own Liquid filters to broadcasts and sequence emails. Full example and common mistakes.

Source: https://sendbroadcast.net/docs/plugins-hook-liquid-filters

> Coming in Broadcast 3.0. Until then, this page applies only to the Upcoming (edge) build.

Use this hook to change how a value looks in an email. A [merge tag](https://sendbroadcast.net/docs/plugins-hook-merge-tags) makes a value. A filter changes a value that is already there.

## How it works

You write a filter in an email:

```liquid
Your balance: {{ subscriber.data.balance | local_money_format: "EUR" }}
```

The filter name is your plugin ID and the filter name, joined with `_`. `.` and `-` become `_`. So the filter `format` in `local.money` is `local_money_format`.

Broadcast collects all the different inputs in a batch and calls your function once. If 100 people have the same balance, you get that input once.

## Full example: money

`manifest.json`:

```json
{
  "id": "local.money",
  "name": "Money",
  "version": "1.0.0",
  "requires": { "broadcast": ">=3.0.0 <4.0.0", "pluginApi": "1" },
  "hooks": {
    "liquidFilters": ["format"]
  }
}
```

`dist/main.js`:

```javascript
export default definePlugin({
  liquidFilters: {
    async format({ items }) {
      return items.map(({ input, args }) => {
        const amount = Number(input);
        const currency = args[0] ?? "USD";
        if (Number.isNaN(amount)) return input;

        return new Intl.NumberFormat("en", { style: "currency", currency }).format(amount);
      });
    },
  },
});
```

With the input `19.5` and the argument `"EUR"`, the result is `€19.50`.

## What you get and return

You get this:

```json
{
  "name": "format",
  "items": [
    { "input": "19.5", "args": ["EUR"] },
    { "input": "abc", "args": [] }
  ]
}
```

You return an array with **one output for each item, in the same order**:

```json
["€19.50", "abc"]
```

## Common mistakes

**You return the wrong number of items.** Each output is matched by its place. If you drop an item, the outputs after it land on the wrong input. Always use `items.map`.

**You treat the input as a number.** Inputs and arguments are strings. Use `Number(input)`, and return the input as it was if it is not a number.

**You use the filter in a test send.** Plugin hooks do not run in transactional emails or test sends.

**You expect a failure to stop the email.** Filters have 5 seconds and fail open: the value is empty and the email goes out. HTML output works as for [merge tags](https://sendbroadcast.net/docs/plugins-hook-merge-tags#html-values).
