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

# Strategies

> Tokenize, hash, mask, or redact, chosen per entity type or per category.

Every detected value is replaced by one of four strategies.

| Strategy | Result | Restorable |
| - | - | - |
| `tokenize` | `[[email:f098b0367449]]` | Yes |
| `hash` | `[[email#96b8a05fd30e]]`, keyed | No |
| `mask` | `**** **** **** 3456`, shape preserved | No |
| `redact` | `[REDACTED:card_cvv]` | No |

## Choosing

Pick a strategy per entity type or per category. A type wins over its category.

<CodeGroup>
  ```ts TypeScript theme={null}
  {
    cloak: {
      context,
      strategies: {
        payment_card: { strategy: "mask", keepLast: 4 },
        email: "hash",
        pii: "tokenize",
      },
    },
  }
  ```

  ```python Python theme={null}
  CloakOptions(
      context=context,
      strategies={
          "payment_card": MaskStrategy(keep_last=4),
          "email": "hash",
          "pii": "tokenize",
      },
  )
  ```
</CodeGroup>

## Defaults

Anything you do not choose is **tokenized**, with two exceptions that are **redacted** and never stored:

* **Credentials** (passwords, API keys and tokens, recovery codes). Keeping a secret recoverable is keeping a secret, and nothing downstream needs it back.
* **Card verification codes.** They must not be stored at all after authorisation.

You can override either.

## Tokenize

A token is `[[<type>:<hex>]]`. The same value under the same context always gets the same token, so a model can tell that two mentions are one email without reading it. The token is a keyed digest of the value, so it cannot be forged or guessed. The original is kept in the [vault](/cloak/identity-and-vault) and comes back on restore.

## Hash

A hash is one-way and keyed. It is not bound to a context, so the same value hashes the same way for every subject, which is what makes it usable for counting and joining. It is keyed rather than a bare digest because an unkeyed hash of a phone number or a national id can be reversed by hashing every candidate.

`length` sets how many hex characters are kept, from 8 to 64. The default is 12.

## Mask

A mask hides letters and digits and keeps everything else, so a card number still reads as four groups and a phone number keeps its spaces.

| Setting | Meaning |
| - | - |
| `keepFirst` | Leading letters or digits left visible. Defaults to 1 for email, otherwise 0. |
| `keepLast` | Trailing letters or digits left visible. Defaults to 4 for cards, phone numbers, bank accounts, IBANs, government ids, and tax ids, otherwise 0. |
| `maskChar` | The single character written over a hidden one. Defaults to `*`. |

An email keeps its domain and masks only the part before the `@`. A mask never turns into a copy: asking to keep more characters than the value has hides all of it instead.

<Note>
  Four visible digits is what a person recognises their own account by, and it is what PCI DSS allows a display to keep of a card number.
</Note>

## Redact

A redaction leaves a label, `[REDACTED:<type>]` by default. Set `replacement` to use your own text.

```ts theme={null}
strategies: { email: { strategy: "redact", replacement: "<hidden>" } }
```

## Validation

The table is checked before any text is touched. An unknown type or category, an unknown strategy, a negative `keepLast`, a `maskChar` that is not one character, or a hash `length` outside 8 to 64 throws immediately, rather than after part of a payload has already been tokenized.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.