nansen-cli 1.17.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/package.json +5 -3
  3. package/skills/nansen-dca-tracker/SKILL.md +38 -0
  4. package/skills/nansen-defi-positions/SKILL.md +37 -0
  5. package/skills/nansen-exit-signals/SKILL.md +39 -0
  6. package/skills/nansen-fund-tracker/SKILL.md +35 -0
  7. package/skills/nansen-general-search/SKILL.md +34 -0
  8. package/skills/nansen-holder-analysis/SKILL.md +38 -0
  9. package/skills/nansen-perp-screener/SKILL.md +32 -0
  10. package/skills/nansen-perp-trader-profile/SKILL.md +39 -0
  11. package/skills/nansen-polymarket-deep-dive/SKILL.md +50 -0
  12. package/skills/nansen-polymarket-insider-scan/SKILL.md +62 -0
  13. package/skills/nansen-polymarket-trader-profile/SKILL.md +43 -0
  14. package/skills/nansen-portfolio-tracker/SKILL.md +36 -0
  15. package/skills/nansen-prediction-markets/SKILL.md +47 -0
  16. package/skills/nansen-sm-cross-chain-flows/SKILL.md +27 -0
  17. package/skills/nansen-smart-alerts/SKILL.md +137 -0
  18. package/skills/nansen-smart-money-alpha/SKILL.md +43 -0
  19. package/skills/nansen-smart-money-tracker/SKILL.md +71 -0
  20. package/skills/nansen-smart-money-trend/SKILL.md +30 -0
  21. package/skills/nansen-token-research/SKILL.md +90 -0
  22. package/skills/nansen-token-screener/SKILL.md +54 -0
  23. package/skills/nansen-token-transfer-analysis/SKILL.md +40 -0
  24. package/skills/nansen-trading/SKILL.md +100 -0
  25. package/skills/nansen-wallet-batch/SKILL.md +26 -0
  26. package/skills/nansen-wallet-clustering/REFERENCE.md +43 -0
  27. package/skills/nansen-wallet-clustering/SKILL.md +46 -0
  28. package/skills/nansen-wallet-deep-dive/SKILL.md +45 -0
  29. package/skills/nansen-wallet-keychain-migration/SKILL.md +183 -0
  30. package/skills/nansen-wallet-manager/SKILL.md +140 -0
  31. package/skills/nansen-wallet-profiler/SKILL.md +98 -0
  32. package/skills/nansen-web-fetcher/SKILL.md +50 -0
  33. package/skills/nansen-web-searcher/SKILL.md +39 -0
  34. package/src/api.js +76 -3
  35. package/src/cli.js +176 -14
  36. package/src/commands/alerts.js +717 -0
  37. package/src/schema.json +164 -1
  38. package/src/telemetry.js +237 -0
  39. package/src/update-check.js +2 -2
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: nansen-wallet-deep-dive
3
+ description: "Who is this wallet and what have they been doing? Identity labels, balance, PnL summary, recent transactions, perp positions, and counterparties."
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - NANSEN_API_KEY
9
+ bins:
10
+ - nansen
11
+ primaryEnv: NANSEN_API_KEY
12
+ install:
13
+ - kind: node
14
+ package: nansen-cli
15
+ bins: [nansen]
16
+ allowed-tools: Bash(nansen:*)
17
+ ---
18
+
19
+ # Wallet Analysis
20
+
21
+ **Answers:** "Who is this wallet and what have they been doing?"
22
+
23
+ ```bash
24
+ ADDR=<address> CHAIN=ethereum
25
+
26
+ nansen research profiler labels --address $ADDR --chain $CHAIN
27
+ # → label, category (e.g. "Smart Trader", "Fund", "Public Figure", ENS names)
28
+
29
+ nansen research profiler balance --address $ADDR --chain $CHAIN
30
+ # → token_symbol, token_name, token_amount, price_usd, value_usd per holding
31
+
32
+ nansen research profiler pnl-summary --address $ADDR --chain $CHAIN --days 30
33
+ # → realized_pnl_usd, realized_pnl_percent, win_rate, traded_token_count, traded_times, top5_tokens
34
+
35
+ nansen research profiler transactions --address $ADDR --chain $CHAIN --limit 20
36
+ # → block_timestamp, method, tokens_sent, tokens_received, volume_usd, source_type
37
+
38
+ nansen research profiler perp-positions --address $ADDR
39
+ # → asset_positions, margin_summary_account_value_usd, margin_summary_total_margin_used_usd
40
+
41
+ nansen research profiler counterparties --address $ADDR --chain $CHAIN --days 30
42
+ # → counterparty_address, counterparty_address_label, interaction_count, total_volume_usd, volume_in/out_usd
43
+ ```
44
+
45
+ perp-positions returns Hyperliquid data — returns empty if the wallet has no open perps.
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: nansen-wallet-keychain-migration
3
+ description: Migrate an existing nansen-cli wallet from insecure password storage (env files, .credentials) to the new secure keychain-backed flow.
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - NANSEN_API_KEY
9
+ bins:
10
+ - nansen
11
+ primaryEnv: NANSEN_API_KEY
12
+ install:
13
+ - kind: node
14
+ package: nansen-cli
15
+ bins: [nansen]
16
+ allowed-tools: Bash(nansen:*)
17
+ ---
18
+
19
+ # Wallet Migration — Old Flow to Secure Keychain
20
+
21
+ Use this skill when a user already has a nansen-cli wallet set up with the
22
+ **old** password storage method and wants to migrate to the new secure flow.
23
+
24
+ ## When to use
25
+
26
+ - User mentions they stored their password in `~/.nansen/.env`, a `.env` file, or `memory.md`
27
+ - User gets the stderr warning: `⚠ Password loaded from insecure .credentials file`
28
+ - User asks to "secure my wallet" or "migrate to keychain"
29
+ - User created a wallet before the keychain update was released
30
+
31
+ ## Detect current state
32
+
33
+ `wallet show` only displays addresses and does NOT load or check the password.
34
+ To detect the actual password situation, check for stored password sources:
35
+
36
+ ```bash
37
+ # 1. Check if a wallet exists at all
38
+ nansen wallet list 2>&1
39
+
40
+ # 2. Check for insecure password stores
41
+ ls -la ~/.nansen/.env 2>/dev/null && echo "FOUND: ~/.nansen/.env (insecure)"
42
+ ls -la ~/.nansen/wallets/.credentials 2>/dev/null && echo "FOUND: .credentials file (insecure)"
43
+
44
+ # 3. Try an operation that requires the password (without setting env var)
45
+ nansen wallet export default 2>&1
46
+ ```
47
+
48
+ Interpret the `export` output:
49
+ - `⚠ Password loaded from ~/.nansen/wallets/.credentials` on stderr → needs migration (Path B)
50
+ - Export succeeds silently → password is in keychain, no migration needed
51
+ - `PASSWORD_REQUIRED` JSON error → password not persisted anywhere (Path C or D)
52
+
53
+ ## Migration paths
54
+
55
+ ### Path A: Password in `~/.nansen/.env` (old skill pattern)
56
+
57
+ The previous wallet skill told agents to write the password to `~/.nansen/.env`.
58
+
59
+ **Step 1 — Ask the human for their password:**
60
+
61
+ > "Your wallet password is currently stored in ~/.nansen/.env, which is insecure.
62
+ > I can migrate it to your OS keychain. Please confirm the password you used when
63
+ > creating the wallet, or I can read it from ~/.nansen/.env if you authorize it."
64
+
65
+ **Step 2 — Migrate:**
66
+
67
+ The `source` and `nansen wallet secure` MUST run in the same shell so the env
68
+ var is available to the node process:
69
+
70
+ ```bash
71
+ source ~/.nansen/.env 2>/dev/null && nansen wallet secure
72
+ ```
73
+
74
+ **Step 3 — Verify the password actually decrypts the wallet:**
75
+
76
+ ```bash
77
+ # Unset env var to prove keychain works, then export to verify decryption
78
+ unset NANSEN_WALLET_PASSWORD
79
+ nansen wallet export default 2>&1
80
+ ```
81
+
82
+ If export succeeds (shows private keys), the migration worked. If it shows
83
+ `Incorrect password`, the wrong password was migrated — run `nansen wallet
84
+ forget-password` and retry with the correct password.
85
+
86
+ **Step 4 — Clean up the insecure file:**
87
+
88
+ ```bash
89
+ rm -f ~/.nansen/.env
90
+ ```
91
+
92
+ ### Path B: Password in `.credentials` file (auto-saved fallback)
93
+
94
+ This happens when `wallet create` couldn't access the OS keychain (containers, CI).
95
+
96
+ ```bash
97
+ nansen wallet secure
98
+ ```
99
+
100
+ If the keychain is still unavailable (e.g. containerized Linux without D-Bus),
101
+ `nansen wallet secure` will explain the situation and suggest alternatives.
102
+
103
+ After migrating, verify decryption works:
104
+
105
+ ```bash
106
+ nansen wallet export default 2>&1
107
+ ```
108
+
109
+ ### Path C: Password only in `NANSEN_WALLET_PASSWORD` env var
110
+
111
+ ```bash
112
+ # Persist the env var password to keychain
113
+ nansen wallet secure
114
+ ```
115
+
116
+ Then verify without the env var:
117
+
118
+ ```bash
119
+ unset NANSEN_WALLET_PASSWORD
120
+ nansen wallet export default 2>&1
121
+ ```
122
+
123
+ ### Path D: Password lost entirely
124
+
125
+ The password cannot be recovered. The wallet's private keys are encrypted with
126
+ AES-256-GCM and the password is not stored anywhere recoverable.
127
+
128
+ **Tell the human:**
129
+
130
+ > "Your wallet password cannot be recovered. If you have funds in this wallet,
131
+ > they may be inaccessible. You can create a new wallet and transfer any remaining
132
+ > accessible funds."
133
+
134
+ ```bash
135
+ # Create a fresh wallet (human must provide a new password)
136
+ NANSEN_WALLET_PASSWORD="<new_password_from_user>" nansen wallet create --name new-wallet
137
+ ```
138
+
139
+ ## Post-migration verification
140
+
141
+ After any migration, confirm the password was migrated correctly by proving
142
+ the keychain password can actually decrypt the wallet:
143
+
144
+ ```bash
145
+ # Unset env var to prove keychain works
146
+ unset NANSEN_WALLET_PASSWORD
147
+
148
+ # This MUST succeed — it proves the keychain password decrypts the wallet
149
+ nansen wallet export default 2>&1
150
+ ```
151
+
152
+ If export shows `Incorrect password`, the wrong password was saved to the
153
+ keychain. Fix with:
154
+
155
+ ```bash
156
+ nansen wallet forget-password
157
+ NANSEN_WALLET_PASSWORD="<correct_password>" nansen wallet secure
158
+ ```
159
+
160
+ If `stderr` still shows the `.credentials` warning, the keychain migration did
161
+ not succeed — check if the OS keychain service is running (`secret-tool` on Linux,
162
+ `security` on macOS).
163
+
164
+ ## Forget password (all stores)
165
+
166
+ If the user wants to remove their persisted password entirely:
167
+
168
+ ```bash
169
+ nansen wallet forget-password
170
+ ```
171
+
172
+ This clears the password from both OS keychain and `.credentials` file. Future
173
+ wallet operations will require `NANSEN_WALLET_PASSWORD` env var or re-running
174
+ `nansen wallet secure`.
175
+
176
+ ## Critical rules for agents
177
+
178
+ - **NEVER generate a password** — always ask the human
179
+ - **NEVER store the password** in files, memory, logs, or conversation history
180
+ - **NEVER use `--human` flag** — interactive prompts break agents
181
+ - If the human authorizes reading `~/.nansen/.env`, read it in the same command
182
+ (`source ~/.nansen/.env && nansen wallet secure`) — do not echo or log the value
183
+ - **ALWAYS verify after migration** with `nansen wallet export default` — `wallet show` does NOT prove the password works (it never loads the password)
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: nansen-wallet-manager
3
+ description: Wallet management — create, list, show, export, send, delete. Use when creating wallets, checking balances, or sending tokens.
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - NANSEN_API_KEY
9
+ bins:
10
+ - nansen
11
+ primaryEnv: NANSEN_API_KEY
12
+ install:
13
+ - kind: node
14
+ package: nansen-cli
15
+ bins: [nansen]
16
+ allowed-tools: Bash(nansen:*)
17
+ ---
18
+
19
+ # Wallet
20
+
21
+ ## Auth Setup
22
+
23
+ ```bash
24
+ # Save API key (non-interactive)
25
+ nansen login --api-key <key>
26
+ # Or via env var:
27
+ NANSEN_API_KEY=<key> nansen login
28
+
29
+ # Verify
30
+ nansen research profiler labels --address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --chain ethereum
31
+ ```
32
+
33
+ ## Wallet Creation (Two-Step Agent Flow)
34
+
35
+ Wallet creation requires a password from the **human user**. The agent must NOT generate or store the password itself.
36
+
37
+ > **Step 1 (Agent → Human):** Ask the user to provide a wallet password (minimum 12 characters).
38
+ >
39
+ > **Step 2 (Agent executes):** Run the create command with the password the user gave you.
40
+
41
+ ```bash
42
+ NANSEN_WALLET_PASSWORD="<password_from_user>" nansen wallet create
43
+ ```
44
+
45
+ After creation, the CLI automatically saves the password:
46
+ - **OS keychain** (macOS Keychain, Linux secret-tool, Windows Credential Manager) — secure, preferred
47
+ - **~/.nansen/wallets/.credentials file** — insecure fallback when no keychain is available (e.g. containers, CI)
48
+
49
+ **All future wallet operations retrieve the password automatically** — no env var or human input needed.
50
+
51
+ If the `.credentials` file fallback is used, the CLI prints a warning on every operation. To migrate to secure storage later, run `nansen wallet secure`.
52
+
53
+ ### Password resolution order (automatic)
54
+
55
+ 1. `NANSEN_WALLET_PASSWORD` env var (if set)
56
+ 2. OS keychain (saved automatically on wallet create)
57
+ 3. `~/.nansen/wallets/.credentials` file (insecure fallback, with warning)
58
+ 4. Structured JSON error with instructions (if none available)
59
+
60
+ ### Critical rules for agents
61
+
62
+ - **NEVER generate a password yourself** — always ask the human user
63
+ - **NEVER store the password** in files, memory, logs, or conversation history
64
+ - **NEVER use `--human` flag** — that enables interactive prompts which agents cannot handle
65
+ - After wallet creation, you do NOT need the password for future operations — the keychain handles it
66
+ - If you get a `PASSWORD_REQUIRED` error, ask the user to provide their password again
67
+
68
+ ## Create
69
+
70
+ ```bash
71
+ # Ask the user for a password first, then:
72
+ NANSEN_WALLET_PASSWORD="<password_from_user>" nansen wallet create
73
+ # Or with a custom name:
74
+ NANSEN_WALLET_PASSWORD="<password_from_user>" nansen wallet create --name trading
75
+ ```
76
+
77
+ ## List & Show
78
+
79
+ ```bash
80
+ nansen wallet list
81
+ nansen wallet show <name>
82
+ nansen wallet default <name>
83
+ ```
84
+
85
+ ## Send
86
+
87
+ ```bash
88
+ # Send native token (SOL, ETH) — password auto-resolved from keychain
89
+ nansen wallet send --to <addr> --amount 1.5 --chain solana
90
+
91
+ # Send entire balance
92
+ nansen wallet send --to <addr> --chain evm --max
93
+
94
+ # Dry run (preview, no broadcast)
95
+ nansen wallet send --to <addr> --amount 1.0 --chain evm --dry-run
96
+ ```
97
+
98
+ ## Export & Delete
99
+
100
+ ```bash
101
+ # Password auto-resolved from keychain
102
+ nansen wallet export <name>
103
+ nansen wallet delete <name>
104
+ ```
105
+
106
+ ## Forget Password
107
+
108
+ ```bash
109
+ # Remove saved password from all stores (keychain + .credentials file)
110
+ nansen wallet forget-password
111
+ ```
112
+
113
+ ## Migrate to Secure Storage
114
+
115
+ ```bash
116
+ nansen wallet secure
117
+ ```
118
+
119
+ For detailed migration steps (from `~/.nansen/.env`, `.credentials`, or env-var-only setups), see the **nansen-wallet-migration** skill.
120
+
121
+ ## Flags
122
+
123
+ | Flag | Purpose |
124
+ |------|---------|
125
+ | `--to` | Recipient address |
126
+ | `--amount` | Amount to send |
127
+ | `--chain` | `evm` or `solana` |
128
+ | `--max` | Send entire balance |
129
+ | `--dry-run` | Preview without broadcasting |
130
+ | `--human` | Enable interactive prompts (human terminal use only — agents must NOT use this) |
131
+ | `--unsafe-no-password` | Skip encryption (keys stored in plaintext — NOT recommended) |
132
+
133
+ ## Environment Variables
134
+
135
+ | Var | Purpose |
136
+ |-----|---------|
137
+ | `NANSEN_WALLET_PASSWORD` | Wallet encryption password — only needed for initial `wallet create`. After that, the OS keychain handles it. |
138
+ | `NANSEN_API_KEY` | API key (also set via `nansen login --api-key <key>`) |
139
+ | `NANSEN_EVM_RPC` | Custom EVM RPC endpoint |
140
+ | `NANSEN_SOLANA_RPC` | Custom Solana RPC endpoint |
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: nansen-wallet-profiler
3
+ description: Wallet profiler — balance, PnL, labels, transactions, counterparties, related wallets, batch, trace, compare. Use when analysing a specific wallet address or comparing wallets.
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - NANSEN_API_KEY
9
+ bins:
10
+ - nansen
11
+ primaryEnv: NANSEN_API_KEY
12
+ install:
13
+ - kind: node
14
+ package: nansen-cli
15
+ bins: [nansen]
16
+ allowed-tools: Bash(nansen:*)
17
+ ---
18
+
19
+ # Wallet Profiler
20
+
21
+ All commands: `nansen research profiler <sub> [options]`
22
+
23
+ `--address` and `--chain` required for most commands.
24
+
25
+ ## Balance & Identity
26
+
27
+ ```bash
28
+ nansen research profiler balance --address <addr> --chain ethereum
29
+ nansen research profiler labels --address <addr> --chain ethereum
30
+ nansen research profiler search --query "Vitalik"
31
+ ```
32
+
33
+ ## PnL
34
+
35
+ ```bash
36
+ nansen research profiler pnl --address <addr> --chain ethereum --days 30
37
+ nansen research profiler pnl-summary --address <addr> --chain ethereum
38
+ ```
39
+
40
+ ## Transactions & History
41
+
42
+ ```bash
43
+ nansen research profiler transactions --address <addr> --chain ethereum --limit 20
44
+ nansen research profiler historical-balances --address <addr> --chain solana --days 30
45
+ ```
46
+
47
+ ## Relationships
48
+
49
+ ```bash
50
+ nansen research profiler related-wallets --address <addr> --chain ethereum
51
+ nansen research profiler counterparties --address <addr> --chain ethereum --days 30
52
+ ```
53
+
54
+ ## Perps (no --chain)
55
+
56
+ ```bash
57
+ nansen research profiler perp-positions --address <addr>
58
+ nansen research profiler perp-trades --address <addr> --days 7
59
+ ```
60
+
61
+ ## Batch, Trace & Compare
62
+
63
+ ```bash
64
+ # Batch — profile multiple wallets at once
65
+ nansen research profiler batch \
66
+ --addresses "0xabc,0xdef" --chain ethereum \
67
+ --include labels,balance,pnl
68
+
69
+ # Trace — BFS multi-hop counterparty trace (makes N*width API calls)
70
+ nansen research profiler trace --address <addr> --chain ethereum --depth 2 --width 5
71
+
72
+ # Compare — shared counterparties and tokens between two wallets
73
+ nansen research profiler compare --addresses "0xabc,0xdef" --chain ethereum
74
+ ```
75
+
76
+ ## Flags
77
+
78
+ | Flag | Purpose |
79
+ |------|---------|
80
+ | `--address` | Wallet address (required) |
81
+ | `--chain` | Required except for perps and search |
82
+ | `--days` | Lookback period (default 30) |
83
+ | `--limit` | Number of results |
84
+ | `--include` | Batch fields: `labels,balance,pnl` |
85
+ | `--depth` | Trace depth 1-5 (default 2) |
86
+ | `--width` | Trace width — keep low to save credits |
87
+ | `--fields` | Select specific fields |
88
+ | `--table` | Human-readable table output |
89
+ | `--format csv` | CSV export |
90
+
91
+ ## Notes
92
+
93
+ - `pnl-summary` has no pagination support (returns aggregate stats, not a list).
94
+ - `perp-positions` has no pagination support.
95
+ - `labels` has no pagination support — the API ignores `per_page` and always returns all labels for the address. `--limit` is not available for this sub-command.
96
+ - `transactions` caps at per_page=100 (API limit).
97
+ - `trace` makes many API calls — use `--width` conservatively.
98
+ - `batch` accepts `--file <path>` with one address per line as alternative to `--addresses`.
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: nansen-web-fetcher
3
+ description: Fetch and analyze content from one or more URLs using AI (Gemini 2.5 Flash). Use when you have specific URLs and need to extract or summarize their content. Pairs well with `nansen web search` results.
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - NANSEN_API_KEY
9
+ bins:
10
+ - nansen
11
+ primaryEnv: NANSEN_API_KEY
12
+ install:
13
+ - kind: node
14
+ package: nansen-cli
15
+ bins: [nansen]
16
+ allowed-tools: Bash(nansen:*)
17
+ ---
18
+
19
+ # Web Fetch
20
+
21
+ Fetch and analyze content from one or more URLs using Gemini 2.5 Flash with URL context.
22
+
23
+ ```bash
24
+ nansen web fetch https://nansen.ai --question "What products does Nansen offer?"
25
+ nansen web fetch --url https://example.com --url https://other.com --question "Compare these two sites"
26
+ nansen web fetch https://docs.uniswap.org/contracts/v4/overview --question "What changed in v4?"
27
+ ```
28
+
29
+ Positional args and `--url` flags can be combined — all become URLs to fetch.
30
+
31
+ | Flag | Values | Default | Purpose |
32
+ |------|--------|---------|---------|
33
+ | `--url` | URL | — | URL to fetch (repeatable for multiple URLs, up to 20) |
34
+ | `--question` | string | **required** | Question to answer about the URL content |
35
+ | `--pretty` | flag | off | Human-readable JSON |
36
+
37
+ Returns:
38
+ - `analysis` — AI-generated answer to your question
39
+ - `retrieved_urls` — URLs successfully fetched
40
+ - `failed_urls` — URLs that could not be retrieved
41
+
42
+ **Tip:** Combine with `web search` — search first to find relevant URLs, then fetch to get full content.
43
+
44
+ ```bash
45
+ # Find and analyze in two steps
46
+ nansen web search "uniswap v4 launch" --num-results 3 --fields link
47
+ nansen web fetch https://blog.uniswap.org/... --question "What are the key changes?"
48
+ ```
49
+
50
+ **Note:** 30s timeout. Paywalled or bot-blocked pages may appear in `failed_urls`.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: nansen-web-searcher
3
+ description: Search the web for one or more queries in parallel. Use when you need current information, news, prices, or any web content to complement on-chain Nansen data.
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - NANSEN_API_KEY
9
+ bins:
10
+ - nansen
11
+ primaryEnv: NANSEN_API_KEY
12
+ install:
13
+ - kind: node
14
+ package: nansen-cli
15
+ bins: [nansen]
16
+ allowed-tools: Bash(nansen:*)
17
+ ---
18
+
19
+ # Web Search
20
+
21
+ Search the web for one or more queries in parallel via the Serper API.
22
+
23
+ ```bash
24
+ nansen web search "bitcoin price"
25
+ nansen web search "solana ecosystem news" --num-results 5
26
+ nansen web search --query "ethereum ETF" --query "bitcoin ETF" --num-results 3
27
+ ```
28
+
29
+ Positional args and `--query` flags can be combined — all become queries.
30
+
31
+ | Flag | Values | Default | Purpose |
32
+ |------|--------|---------|---------|
33
+ | `--query` | string | — | Query string (repeatable for multiple queries) |
34
+ | `--num-results` | 1–20 | 10 | Results per query |
35
+ | `--pretty` | flag | off | Human-readable JSON |
36
+
37
+ Returns `results[]` — one entry per query, each with `organic[]` (title, link, snippet, date) and optional `knowledge_graph`.
38
+
39
+ **Note:** Some domains are excluded from results (paywalled/unfetchable sites like bloomberg.com, twitter.com). Use `nansen web fetch` to retrieve content from specific URLs.
package/src/api.js CHANGED
@@ -7,9 +7,15 @@ import fs from 'fs';
7
7
  import path from 'path';
8
8
  import { fileURLToPath } from 'url';
9
9
  import { EVM_CHAINS } from './chain-ids.js';
10
+ import { getAnonymousId, TELEMETRY_DISABLED } from './telemetry.js';
10
11
 
11
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
13
 
14
+ function telemetryHeaders() {
15
+ if (TELEMETRY_DISABLED) return {};
16
+ return { 'X-Anonymous-Id': getAnonymousId() };
17
+ }
18
+
13
19
  const { version: packageVersion } = JSON.parse(
14
20
  fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')
15
21
  );
@@ -442,6 +448,7 @@ export class NansenAPI {
442
448
  'Content-Type': 'application/json',
443
449
  'X-Client-Type': 'nansen-cli',
444
450
  'X-Client-Version': packageVersion,
451
+ ...telemetryHeaders(),
445
452
  'Payment-Signature': signature,
446
453
  ...this.defaultHeaders,
447
454
  ...options.headers,
@@ -493,11 +500,12 @@ export class NansenAPI {
493
500
  ...(!isGet && { 'Content-Type': 'application/json' }),
494
501
  'X-Client-Type': 'nansen-cli',
495
502
  'X-Client-Version': packageVersion,
503
+ ...telemetryHeaders(),
496
504
  ...(this.apiKey ? { 'apikey': this.apiKey } : {}),
497
505
  ...this.defaultHeaders,
498
506
  ...options.headers
499
507
  },
500
- ...(!isGet && { body: JSON.stringify(NansenAPI.cleanBody(body)) })
508
+ ...(!isGet && method !== 'DELETE' && { body: JSON.stringify(NansenAPI.cleanBody(body)) })
501
509
  });
502
510
  } catch (err) {
503
511
  // Network-level errors - retry these too
@@ -538,12 +546,20 @@ export class NansenAPI {
538
546
  }
539
547
 
540
548
  if (!response.ok) {
541
- let message = data.message || data.error || `API error: ${response.status}`;
549
+ let message = data.message || data.error
550
+ || (typeof data.detail === 'string' ? data.detail : data.detail?.message)
551
+ || `API error: ${response.status}`;
552
+ // nansen-api proxy stringifies nested error dicts via Python str(), producing
553
+ // "{'message': 'actual error', ...}". Extract the inner message if present.
554
+ const nestedMatch = typeof message === 'string' && message.match(/['"]message['"]\s*:\s*['"](.*?)['"]/);
555
+ if (nestedMatch) message = nestedMatch[1];
542
556
  const code = statusToErrorCode(response.status, data);
543
557
  const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'));
544
558
 
545
559
  // Enhance messages for specific error codes
546
- if (code === ErrorCode.UNSUPPORTED_FILTER) {
560
+ if (code === ErrorCode.UNAUTHORIZED) {
561
+ message = this.apiKey ? message : 'Not logged in. Run: nansen login';
562
+ } else if (code === ErrorCode.UNSUPPORTED_FILTER) {
547
563
  message = message.replace(/\.+$/, '') + '. This filter is not supported for this token/chain combination. Do not retry.';
548
564
  } else if (code === ErrorCode.CREDITS_EXHAUSTED) {
549
565
  message = message.replace(/\.+$/, '') + '. No retry will help. Check your Nansen dashboard for credit balance.';
@@ -819,6 +835,31 @@ export class NansenAPI {
819
835
  return this.request('/api/v1/search/general', body);
820
836
  }
821
837
 
838
+ async webSearch(params = {}) {
839
+ const { queries, numResults = 10 } = params;
840
+ if (!queries || queries.length === 0) {
841
+ throw new NansenError('At least one query is required', ErrorCode.MISSING_PARAM);
842
+ }
843
+ return this.request('/api/v1/search/web-search', {
844
+ queries,
845
+ num_results: numResults,
846
+ }, { cache: false });
847
+ }
848
+
849
+ async webFetch(params = {}) {
850
+ const { urls, question } = params;
851
+ if (!urls || urls.length === 0) {
852
+ throw new NansenError('At least one URL is required', ErrorCode.MISSING_PARAM);
853
+ }
854
+ if (!question) {
855
+ throw new NansenError('A question is required', ErrorCode.MISSING_PARAM);
856
+ }
857
+ return this.request('/api/v1/search/web-fetch', {
858
+ urls,
859
+ question,
860
+ }, { cache: false });
861
+ }
862
+
822
863
  async addressHistoricalBalances(params = {}) {
823
864
  const { address, chain = 'ethereum', filters = {}, orderBy, pagination, days = 30 } = params;
824
865
  if (address) {
@@ -1264,6 +1305,38 @@ export class NansenAPI {
1264
1305
  wallet_address: walletAddress
1265
1306
  });
1266
1307
  }
1308
+
1309
+ // ============= Smart Alert Endpoints =============
1310
+
1311
+ async alertsList(params = {}) {
1312
+ const defined = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== undefined));
1313
+ const qs = Object.keys(defined).length > 0 ? '?' + new URLSearchParams(defined).toString() : '';
1314
+ return this.request(`/api/v1/smart-alert/list${qs}`, {}, { method: 'GET' });
1315
+ }
1316
+
1317
+ async alertsCreate(params = {}) {
1318
+ return this.request('/api/v1/smart-alert', params);
1319
+ }
1320
+
1321
+ async alertsUpdate(params = {}) {
1322
+ return this.request('/api/v1/smart-alert', params, { method: 'PATCH' });
1323
+ }
1324
+
1325
+ async alertsToggle(params = {}) {
1326
+ return this.request('/api/v1/smart-alert/toggle', params, { method: 'PATCH' });
1327
+ }
1328
+
1329
+ async alertsGet(id) {
1330
+ // TODO: replace with GET /api/v1/smart-alert/{id} once a get-by-id endpoint exists.
1331
+ // Fetching the full list does not scale for users with many alerts.
1332
+ const result = await this.alertsList();
1333
+ const alerts = Array.isArray(result) ? result : result?.alerts ?? result?.data ?? [];
1334
+ return alerts.find(a => a.id === id) ?? null;
1335
+ }
1336
+
1337
+ async alertsDelete(alertId) {
1338
+ return this.request(`/api/v1/smart-alert/${encodeURIComponent(alertId)}`, {}, { method: 'DELETE' });
1339
+ }
1267
1340
  }
1268
1341
 
1269
1342
  export default NansenAPI;