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

# Profiles

> Look up wallet profiles, search your user base, update identity properties, and manage labels using the Formo CLI profiles commands.

The `formo profiles` command group lets you look up individual wallet profiles, search your user base, merge-update identity properties, and manage labels.

## Lifecycle Threshold Options

`profiles get` and `profiles search` accept optional lifecycle threshold overrides:

| Option | Type | Description |
| - | - | - |
| `--new-window-days` | `number` | Override lifecycle new-user window in days |
| `--churn-window-days` | `number` | Override lifecycle churn window in days |
| `--power-user-min-active-days` | `number` | Override lifecycle power-user minimum active days |
| `--power-user-window-days` | `number` | Override lifecycle power-user window in days |
| `--resurrected-gap-days` | `number` | Override lifecycle resurrected gap in days |
| `--at-risk-min-days-inactive` | `number` | Override lifecycle at-risk minimum inactive days |
| `--at-risk-prior-active-days-threshold` | `number` | Override lifecycle at-risk prior active days threshold |

***

## `formo profiles get <address>`

Fetch a single wallet profile by address or ENS name.

<Note>
  Requires `profiles:read` scope on your API key.
</Note>

### Options

| Option | Type | Required | Description |
| - | - | - | - |
| `--expand` | `string` | ❌ | Comma-separated fields to expand: `apps`, `chains`, `tokens`, `labels` |
| `--timestamp` | `string` | ❌ | ISO-8601 timestamp; return the closest stored wallet-enrichment snapshot |

The lifecycle threshold options listed above are also supported.

### Examples

```bash theme={null}
formo profiles get 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
formo profiles get vitalik.eth --expand labels,chains
formo profiles get vitalik.eth --expand apps,chains,tokens,labels --churn-window-days 30
formo profiles get vitalik.eth --timestamp 2025-06-21T10:03:00Z
```

***

## `formo profiles search`

Search wallet profiles with optional filters, sorting, free-text search, and pagination.

<Note>
  Requires `profiles:read` scope on your API key.
</Note>

### Options

| Option | Type | Required | Description |
| - | - | - | - |
| `--address` | `string` | ❌ | Filter by wallet address |
| `--search` | `string` | ❌ | Free-text search across address and identity fields |
| `--timestamp` | `string` | ❌ | ISO-8601 timestamp; requires `--address` and returns the closest stored wallet-enrichment snapshot |
| `--page` | `number` | ❌ | Page number, 1-indexed |
| `--size` | `number` | ❌ | Page size |
| `--order-by` | `enum` | ❌ | Field to sort by |
| `--order-dir` | `enum` | ❌ | Sort direction: `asc` or `desc` |
| `--expand` | `string` | ❌ | Comma-separated fields to expand |
| `--filters` | `string` | ❌ | JSON array of canonical `{field, op, value}` filter objects |
| `--logic` | `enum` | ❌ | Combine filters with `and` or `or` |

The lifecycle threshold options listed above are also supported.

### `--order-by` Values

`last_onchain`, `first_onchain`, `net_worth_usd`, `updated_at`, `tx_count`, `first_seen`, `last_seen`, `num_sessions`, `revenue`, `volume`, `points`

### Examples

```bash theme={null}
# List first 10 profiles
formo profiles search --size 10

# Search text fields
formo profiles search --search vitalik --size 5

# Return the closest stored snapshot for one wallet
formo profiles search \
  --address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  --timestamp 2025-06-21T10:03:00Z

# Top 5 profiles by net worth
formo profiles search --order-by net_worth_usd --order-dir desc --size 5

# Search with a typed filter condition
formo profiles search \
  --filters '[{"field":"users.net_worth_usd","op":"gt","value":10000}]' \
  --size 20

# Search profiles matching either condition
formo profiles search \
  --filters '[{"field":"users.net_worth_usd","op":"gt","value":10000},{"field":"users.volume","op":"gt","value":1000}]' \
  --logic or \
  --size 20

# Filter by onchain balance on Ethereum
formo profiles search \
  --filters '[{"field":"chains.balance","op":"gt","value":1000,"chain_id":"1"}]' \
  --size 20
```

The response is a paginated envelope: `{ data, total, page, size, has_more }`.

When `--timestamp` is present, wallet-enrichment fields come from the stored base snapshot closest to that instant. If two snapshots are equally close, the later snapshot is returned. Expanded chains, apps, and tokens come from the selected profiling batch. Project engagement fields, project-defined identity overrides, and labels remain current. Omitting `--timestamp` returns the latest profile.

### Filters

`--filters` accepts a JSON array of canonical filter objects. Resource filters use a stable `field` plus named qualifier properties (`chain_id`, `app_id`, `token_address`, `scope`, `tag_id`):

```json theme={null}
[
  { "field": "users.net_worth_usd", "op": "gt", "value": 10000 },
  { "field": "chains.balance", "op": "gte", "value": 1000, "chain_id": "1" },
  { "field": "apps.balance", "op": "gt", "value": 500, "app_id": "uniswap-v3" },
  { "field": "tokens.balance", "op": "gt", "value": 0, "token_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "scope": "any" },
  { "field": "labels.value", "op": "eq", "value": "tier-1", "tag_id": "vip" },
  { "field": "labels.value", "op": "gte", "value": "10000", "tag_id": "defi.lender" }
]
```

<Warning>
  `field` must be a stable typed path: `users.{attribute}` for user/profile/social fields, or one of `chains.balance`, `apps.balance`, `tokens.balance`, `labels.value` for resource filters. Bare names like `net_worth_usd` are rejected because the API ignores them, and the retired identifier-in-path spellings (`chains.1.balance`, `apps.uniswap-v3.balance`, `tokens.0x….balance`, `labels.vip`) are rejected with a `400`; put identifiers in the qualifier properties instead.
</Warning>

### Filter Operators

`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `contains`, `startsWith`, `endsWith`, `notEmpty`, `isEmpty`

The long-form spellings (`equals`, `notEquals`, `greater`, `greaterOrEqual`, `less`, `lessOrEqual`, `notIn`, `includes`) are retired. The API rejects them with a `400` naming the token. Use only the canonical operators above.

The vocabulary is shared, but each field implements a subset — an unsupported pairing is a `400`:

| Field class | Supported operators |
| - | - |
| `chains.balance`, `apps.balance`, `tokens.balance` | `eq`, `neq`, `gt`, `gte`, `lt`, `lte` — the value must be a JSON number, not a numeric string |
| `labels.value` | comparison operators plus `contains` (case-insensitive) |
| Numeric profile metrics (`users.net_worth_usd`, `users.volume`, `users.revenue`, `users.points`) | comparison operators |
| Routable string attributes (`users.device`, `users.os`, `users.referrer`, `users.utm_*`, `users.click_id`, and the `first_*`/`last_*` attribution variants) | the full vocabulary; `contains`, `startsWith` and `endsWith` match case-sensitively |
| Social fields (`users.twitter`, `users.email`, `users.farcaster`, …) | `contains` (case-insensitive) and `notEmpty`; `startsWith`, `endsWith` and `isEmpty` are rejected |
| `users.paid_source` (and its `first_`/`last_` variants) | `eq`, `neq`, `in`, `nin`, `notEmpty`, `isEmpty` — it is a fixed ad-network enum |
| `users.lifecycle` | `eq` (one stage) and `in` (a list of stages) |

`notEmpty` and `isEmpty` are value-less existence checks; the `value` is ignored.

***

## `formo profiles update <address>`

Merge-update identity properties on a single wallet profile. Provide `--properties`, `--unset`, or both.

<Note>
  Requires `profiles:write` scope on your API key.
</Note>

### Options

| Option | Type | Required | Description |
| - | - | - | - |
| `--properties` | `string` | One of the two | JSON object of properties to merge; a `null` value deletes (unsets) that property |
| `--unset` | `string` | One of the two | Comma-separated property keys to delete, e.g. `email,twitter` (shorthand for `null` values in `--properties`) |

Allowed property keys:

`user_id`, `display_name`, `email`, `farcaster`, `discord`, `twitter`, `telegram`, `instagram`, `website`, `github`, `linkedin`, `facebook`, `tiktok`, `youtube`, `reddit`, `avatar`, `description`, `location`, `ens`, `lens`, `basenames`, `linea`

```bash theme={null}
formo profiles update 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  --properties '{"display_name":"Vitalik","twitter":"VitalikButerin"}'
```

Delete properties by key, or mix set and unset in one call:

```bash theme={null}
formo profiles update 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  --unset email,twitter

formo profiles update 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  --properties '{"display_name":"alice.eth"}' --unset email
```

<Note>
  `--unset` takes precedence when the same key also appears in `--properties`. A deleted property reads as `null` everywhere, including over any globally-enriched fallback value and in historical snapshot reads, until a new value is set. A deleted `location` falls back to device geo. `user_id` cannot be unset (it participates in identity stitching).
</Note>

***

## `formo profiles properties batch`

Batch update first-party profile properties for up to 100 wallets.

<Note>
  Requires `profiles:write` scope on your API key.
</Note>

### Options

| Option | Type | Required | Description |
| - | - | - | - |
| `--rows` | `string` | ✅ | JSON array of flat `{address, ...properties}` objects; a `null` value deletes (unsets) that property (`user_id` cannot be unset) |

```bash theme={null}
formo profiles properties batch \
  --rows '[{"address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","display_name":"alice.eth","email":"alice@example.com"}]'
```

Delete properties in a batch with `null` values:

```bash theme={null}
formo profiles properties batch \
  --rows '[{"address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","email":null}]'
```

<Note>
  ENS names are not resolved in batch requests. Use wallet addresses in each `address` field.
</Note>

***

## `formo profiles labels create <address>`

Upsert one or more labels on a wallet profile. Provide either a single label with `--tag-id` or a wallet-local batch with `--labels`.

<Note>
  Requires `profiles:write` scope on your API key.
</Note>

### Options

| Option | Type | Required | Description |
| - | - | - | - |
| `--tag-id` | `string` | ❌ | Label identifier, required unless `--labels` is provided |
| `--value` | `string` | ❌ | Optional label value |
| `--chain-id` | `string` | ❌ | Optional chain identifier the label applies to |
| `--timestamp` | `string` | ❌ | Optional historical ISO-8601 timestamp for the label row |
| `--is-deleted` | `boolean` | ❌ | Backfill a historical label removal tombstone |
| `--labels` | `string` | ❌ | JSON array of `UserLabelInput` objects for this wallet |

### Examples

```bash theme={null}
formo profiles labels create 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --tag-id vip

formo profiles labels create 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  --tag-id tier --value gold --chain-id 1

formo profiles labels create 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  --tag-id tier --timestamp 2024-03-15T00:00:00.000Z --is-deleted

formo profiles labels create 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  --labels '[{"tag_id":"vip"},{"tag_id":"airdrop_eligible","chain_id":"1"}]'
```

***

## `formo profiles labels batch`

Batch upsert labels across up to 100 wallets.

<Note>
  Requires `profiles:write` scope on your API key.
</Note>

### Options

| Option | Type | Required | Description |
| - | - | - | - |
| `--labels` | `string` | ✅ | JSON array of `{address, tag_id, value?, chain_id?, timestamp?, _is_deleted?}` objects |

```bash theme={null}
formo profiles labels batch \
  --labels '[{"address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","tag_id":"vip","value":"tier-1"}]'
```

<Note>
  ENS names are not resolved in batch requests. Use wallet addresses in each `address` field.
</Note>

***

## `formo profiles labels delete <address>`

Delete a label from a wallet profile. Pass `--chain-id` to scope deletion to a chain-specific label.

<Note>
  Requires `profiles:write` scope on your API key.
</Note>

### Options

| Option | Type | Required | Description |
| - | - | - | - |
| `--tag-id` | `string` | ✅ | Label identifier to delete |
| `--chain-id` | `string` | ❌ | Optional chain identifier to scope the deletion |

```bash theme={null}
formo profiles labels delete 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --tag-id vip

formo profiles labels delete 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  --tag-id tier --chain-id 1
```


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