npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@formo/cli

v1.0.0

Published

Formo API CLI — query profiles and analytics data

Readme

@formo/cli

Command-line interface for the Formo API. Manage wallet profiles, alerts, dashboards, charts, contracts, segments, and run analytics SQL — directly from your terminal or via AI agents.

Installation

npm install -g @formo/cli
# or use without installing:
npx @formo/cli

Authentication

Save your API key locally:

formo login <apiKey>

Or set the FORMO_API_KEY environment variable — it takes precedence over the saved config:

export FORMO_API_KEY=formo_abc123

Get your API key from Settings → API Keys in the Formo dashboard.


Auth commands

formo login [apiKey]

Save your API key to ~/.config/formo/config.json. Validates the key against the API and stores the workspace context.

formo login formo_abc123

formo logout

Remove the saved API key and clear authentication state.

formo logout

formo status

Show current authentication state, workspace, and project ID.

formo status

formo profiles

Wallet profile commands.

profiles get <address>

Fetch a single wallet profile by address or ENS name.

| Option | Description | |---|---| | --expand | Comma-separated fields: apps, chains, tokens, labels |

formo profiles get 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
formo profiles get vitalik.eth --expand labels,chains

profiles search

Search wallet profiles with filters, sorting, and pagination. Returns a PaginatedResponse<Profile>.

| Option | Description | |---|---| | --address | Filter by wallet address | | --page | Page number (1-indexed, default 1) | | --size | Page size (default 100, max 1000) | | --order-by | last_onchain, first_onchain, net_worth_usd, updated_at, tx_count, first_seen, last_seen, num_sessions, revenue, volume, points | | --order-dir | asc or desc | | --expand | Comma-separated fields to expand | | --conditions | JSON array of FilterCondition objects (see below) | | --logic | Combine conditions with and (default) or or |

formo profiles search --size 10
formo profiles search --order-by net_worth_usd --order-dir desc --size 5
formo profiles search --page 2 --size 20
formo profiles search --conditions '[{"field":"users.net_worth_usd","op":"gt","value":10000}]' --size 20
formo profiles search --conditions '[{"field":"users.net_worth_usd","op":"gt","value":10000},{"field":"users.volume","op":"gt","value":1000}]' --logic or --size 20
formo profiles search --conditions '[{"field":"chains.1.balance","op":"gt","value":1000}]' --size 20

profiles update <address>

Merge-update identity properties on a wallet profile.

| Option | Description | |---|---| | --properties | JSON object of properties to merge |

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. Unknown keys are rejected server-side.

formo profiles update 0xd8dA... --properties '{"display_name":"Vitalik","twitter":"VitalikButerin"}'
formo profiles update vitalik.eth --properties '{"email":"[email protected]"}'

Requires profiles:write scope.

profiles labels create <address>

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

| Option | Description | |---|---| | --tag-id | Label identifier (e.g. vip, airdrop_eligible) | | --value | Optional label value (e.g. tier name, country code) | | --chain-id | Optional chain identifier the label applies to | | --labels | JSON array of UserLabelInput objects for batch upsert |

formo profiles labels create 0xd8dA... --tag-id vip
formo profiles labels create 0xd8dA... --tag-id tier --value gold --chain-id 1
formo profiles labels create 0xd8dA... --labels '[{"tag_id":"vip"},{"tag_id":"airdrop_eligible","chain_id":"1"}]'

profiles labels delete <address>

Delete a label from a wallet profile.

| Option | Description | |---|---| | --tag-id | Label identifier to delete (required) | | --chain-id | Optional chain identifier to scope the deletion |

formo profiles labels delete 0xd8dA... --tag-id vip
formo profiles labels delete 0xd8dA... --tag-id tier --chain-id 1

Requires profiles:write scope.


formo alerts

Project alert commands. Requires alerts:read (list/get) or alerts:write (create/update/delete/toggle).

alerts list

List all alerts for the project.

alerts get <alertId>

Get a single alert by ID.

alerts create

| Option | Description | |---|---| | --name | Alert name | | --trigger-type | Trigger type (e.g. event, threshold) | | --trigger-filters | JSON array of trigger filter objects | | --recipient | JSON array of recipient objects | | --secret | Webhook secret |

formo alerts create --name "High value tx" --trigger-type event \
  --trigger-filters '[{"name":"event","operator":"equals","value":"transaction"}]' \
  --recipient '[{"type":"email","value":["[email protected]"]}]'

alerts update <alertId>

Same options as create. Replaces the alert configuration.

alerts delete <alertId>

Delete an alert.

alerts toggle <alertId> --status <active|paused>

Toggle an alert between active and paused.

formo alerts toggle alert_abc123 --status paused

formo boards

Dashboard board commands. Requires boards:read / boards:write.

boards list

List all boards for the project.

boards get <boardId>

Get a single board by ID.

boards create

| Option | Description | |---|---| | --name | Board name | | --description | Optional board description |

formo boards create --name "Revenue Metrics" --description "Weekly revenue tracking"

boards update <boardId>

| Option | Description | |---|---| | --name | New board name | | --description | New board description |

boards delete <boardId>

Delete a board.


formo charts

Chart commands. Charts live inside a board. Requires charts:read / charts:write.

charts list --board-id <boardId>

List all charts in a board.

charts get <chartId> --board-id <boardId>

Get a single chart by ID.

charts create --board-id <boardId> --body '<json>'

Create a chart from a JSON config string.

charts update <chartId> --board-id <boardId> --body '<json>'

Update a chart.

charts delete <chartId> --board-id <boardId>

Delete a chart.


formo contracts

Smart contract commands. Requires contracts:read / contracts:write.

contracts list

List all tracked contracts. Returns { data: Contract[], deploy: { last_deployed_at, diff }, total, page, size, has_more }.

contracts create

| Option | Description | |---|---| | --address | Contract address (0x…) | | --chain | Chain ID (e.g. 1, 137) | | --name | Human-readable contract name | | --abi | Contract ABI as a JSON string | | --events | Events configuration as a JSON string |

formo contracts create --address 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 --chain 1 \
  --name "UNI Token" --abi '[{"type":"event","name":"Transfer","inputs":[]}]' \
  --events '{"Transfer":true}'

contracts update <chain> <address>

| Option | Description | |---|---| | --name | Updated contract name | | --abi | Updated ABI | | --events | Updated events config |

contracts delete <chain> <address>

Remove a tracked contract.


formo segments

User segment commands. Requires segments:read / segments:write.

segments list

List all user segments.

segments create

| Option | Description | |---|---| | --title | Segment title | | --filter-sets | JSON array of filter set strings defining the segment |

segments delete <segmentId>

Delete a user segment.


formo query

query run "<sql>"

Run a SQL query against your Formo analytics data. Returns { data, total, limit, offset, has_more }.

formo query run "SELECT count(*) FROM events"
formo query run "SELECT address, net_worth_usd FROM wallet_profiles ORDER BY net_worth_usd DESC LIMIT 10"

Requires query:read scope.


formo analytics

Pre-built analytics pipes — the same data that powers the Formo dashboard — without writing SQL. Each pipe is a subcommand: formo analytics <pipe>.

Pipes: kpis, event_timeseries, funnel, flow, frequency, lifecycle, retention, revenue_overview, revenue_by_metric, revenue_timeseries, volume_by_metric, top_chains, top_events, top_locations, top_pages, top_sources, top_wallets

| Option | Description | |---|---| | --date-from | Inclusive start date YYYY-MM-DD (default: 7 days before --date-to) | | --date-to | Inclusive end date YYYY-MM-DD (default: today) | | --filters | JSON array of [{field,op,value}]. Use in/notIn with a pipe-delimited value (e.g. "chrome\|firefox") | | --params | JSON object of pipe-specific params merged into the query (e.g. {"limit":10,"group_by":"device"}) |

formo analytics kpis
formo analytics kpis --date-from 2026-04-01 --date-to 2026-04-30 --params '{"group_by":"device"}'
formo analytics funnel --date-from 2026-04-01 --date-to 2026-04-30 --params '{"steps":[{"type":"event","event":"page","name":"page::0","filters":[]},{"type":"track","event":"connect","name":"connect::1","filters":[]}],"window_seconds":86400}'
formo analytics top_wallets --date-from 2026-04-01 --date-to 2026-04-30 --params '{"limit":10}'
formo analytics retention --filters '[{"field":"location","op":"equals","value":"US"}]'

Requires query:read scope. Run formo analytics <pipe> --help for the pipe-specific params accepted via --params.


formo import

import wallets

Bulk-import wallet addresses into the project via the events API.

| Option | Description | |---|---| | --addresses | JSON array of wallet address strings | | --write-key | Project write SDK key |

formo import wallets --addresses '["0xabc...","0xdef..."]' --write-key write_key_xyz

FilterCondition reference

profiles search --conditions accepts a JSON array of filter condition objects:

[
  { "field": "users.net_worth_usd", "op": "gt", "value": 10000 },
  { "field": "chains.1.balance", "op": "gte", "value": 1000 }
]

The field must be a typed path. A bare name like net_worth_usd is silently ignored by the API (no error, no filtering — the search returns everything). Always prefix the field with its type.

| Field | Type | Description | |---|---|---| | field | string | Typed path (see prefixes below) | | op | string | eq, neq, gt, gte, lt, lte, in, nin | | value | any | Value to compare against | | scope | string | (token filters only) any or protocol | | appId | string | (token filters with scope: protocol) e.g. aave-v3 |

| Prefix | Examples | |---|---| | users. | users.net_worth_usd, users.volume, users.revenue, users.points, users.device, users.location, users.lifecycle, users.ens, users.farcaster | | chains. | chains.balance (any chain), chains.1.balance (Ethereum) | | apps. | apps.uniswap-v3.balance | | tokens. | tokens.0xA0b8…48.balance | | labels. | labels.coinbase.verified_account |

Combine multiple conditions with --logic and (default) or --logic or.


Output formats

Every command supports the standard incur output flags:

| Flag | Description | |---|---| | --format <toon\|json\|yaml\|md\|jsonl> | Output format (default: toon) | | --json | Shorthand for --format json | | --verbose | Include the full envelope (ok, data, meta) | | --filter-output <keys> | Filter output by key paths (e.g. data,meta.duration) |

Every list endpoint returns a PaginatedResponse<T> envelope: { data: [...], total, page, size, has_more }. Every error follows: { error: { code, message, doc_url, param?, details? } } — branch on error.code, not message.


Development

# Install dependencies
pnpm install

# Run in development mode
pnpm dev

# Build TypeScript
pnpm build

# Lint
pnpm lint

# Run tests (requires TEST_TOKEN in .env)
pnpm test