@aluvia/sdk 1.0.0 → 1.3.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.
- package/README.md +425 -256
- package/dist/cjs/api/account.js +10 -74
- package/dist/cjs/api/apiUtils.js +80 -0
- package/dist/cjs/api/geos.js +2 -63
- package/dist/cjs/api/request.js +8 -2
- package/dist/cjs/bin/account.js +31 -0
- package/dist/cjs/bin/api-helpers.js +58 -0
- package/dist/cjs/bin/cli.js +245 -0
- package/dist/cjs/bin/close.js +120 -0
- package/dist/cjs/bin/geos.js +10 -0
- package/dist/cjs/bin/mcp-helpers.js +57 -0
- package/dist/cjs/bin/mcp-server.js +220 -0
- package/dist/cjs/bin/mcp-tools.js +90 -0
- package/dist/cjs/bin/open.js +293 -0
- package/dist/cjs/bin/session.js +259 -0
- package/dist/cjs/client/AluviaClient.js +411 -150
- package/dist/cjs/client/BlockDetection.js +486 -0
- package/dist/cjs/client/ConfigManager.js +26 -23
- package/dist/cjs/client/PageLoadDetection.js +175 -0
- package/dist/cjs/client/ProxyServer.js +4 -2
- package/dist/cjs/client/logger.js +4 -0
- package/dist/cjs/client/rules.js +38 -49
- package/dist/cjs/connect.js +117 -0
- package/dist/cjs/errors.js +12 -1
- package/dist/cjs/index.js +5 -1
- package/dist/cjs/session/lock.js +186 -0
- package/dist/esm/api/account.js +2 -66
- package/dist/esm/api/apiUtils.js +71 -0
- package/dist/esm/api/geos.js +2 -63
- package/dist/esm/api/request.js +8 -2
- package/dist/esm/bin/account.js +28 -0
- package/dist/esm/bin/api-helpers.js +53 -0
- package/dist/esm/bin/cli.js +242 -0
- package/dist/esm/bin/close.js +117 -0
- package/dist/esm/bin/geos.js +7 -0
- package/dist/esm/bin/mcp-helpers.js +51 -0
- package/dist/esm/bin/mcp-server.js +185 -0
- package/dist/esm/bin/mcp-tools.js +78 -0
- package/dist/esm/bin/open.js +256 -0
- package/dist/esm/bin/session.js +252 -0
- package/dist/esm/client/AluviaClient.js +384 -156
- package/dist/esm/client/BlockDetection.js +482 -0
- package/dist/esm/client/ConfigManager.js +21 -18
- package/dist/esm/client/PageLoadDetection.js +171 -0
- package/dist/esm/client/ProxyServer.js +5 -3
- package/dist/esm/client/logger.js +4 -0
- package/dist/esm/client/rules.js +36 -49
- package/dist/esm/connect.js +81 -0
- package/dist/esm/errors.js +10 -0
- package/dist/esm/index.js +5 -3
- package/dist/esm/session/lock.js +142 -0
- package/dist/types/api/AluviaApi.d.ts +2 -7
- package/dist/types/api/account.d.ts +1 -16
- package/dist/types/api/apiUtils.d.ts +28 -0
- package/dist/types/api/geos.d.ts +1 -1
- package/dist/types/bin/account.d.ts +1 -0
- package/dist/types/bin/api-helpers.d.ts +20 -0
- package/dist/types/bin/cli.d.ts +2 -0
- package/dist/types/bin/close.d.ts +1 -0
- package/dist/types/bin/geos.d.ts +1 -0
- package/dist/types/bin/mcp-helpers.d.ts +28 -0
- package/dist/types/bin/mcp-server.d.ts +2 -0
- package/dist/types/bin/mcp-tools.d.ts +46 -0
- package/dist/types/bin/open.d.ts +21 -0
- package/dist/types/bin/session.d.ts +11 -0
- package/dist/types/client/AluviaClient.d.ts +51 -4
- package/dist/types/client/BlockDetection.d.ts +96 -0
- package/dist/types/client/ConfigManager.d.ts +6 -1
- package/dist/types/client/PageLoadDetection.d.ts +93 -0
- package/dist/types/client/logger.d.ts +2 -0
- package/dist/types/client/rules.d.ts +18 -0
- package/dist/types/client/types.d.ts +69 -46
- package/dist/types/connect.d.ts +18 -0
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/index.d.ts +7 -5
- package/dist/types/session/lock.d.ts +43 -0
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -5,419 +5,588 @@
|
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
[](./package.json)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
**Stop getting blocked.** Aluvia routes your AI agent's web traffic through premium US mobile carrier IPs — the same IPs used by real people on their phones. Websites trust them, so your agent stops hitting 403s, CAPTCHAs, and rate limits.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
This SDK gives you everything you need:
|
|
11
11
|
|
|
12
|
-
**
|
|
12
|
+
- **CLI for browser automation** — launch headless Chromium sessions from the command line, with JSON output designed for AI agent frameworks
|
|
13
|
+
- **Automatic block detection and unblocking** — the SDK detects 403s, WAF challenges, and CAPTCHAs, then reroutes through Aluvia and reloads the page automatically
|
|
14
|
+
- **Smart routing** — proxy only the sites that block you; everything else goes direct to save cost and latency
|
|
15
|
+
- **Runtime rule updates** — add hostnames to proxy rules on the fly, no restarts or redeployments
|
|
16
|
+
- **Adapters for every tool** — Playwright, Puppeteer, Selenium, Axios, got, and Node's fetch
|
|
17
|
+
- **IP rotation and geo targeting** — rotate IPs or target specific US regions at runtime
|
|
18
|
+
- **REST API wrapper** — manage connections, check usage, and build custom tooling with `AluviaApi`
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Table of contents
|
|
23
|
+
|
|
24
|
+
- [Quick start](#quick-start)
|
|
25
|
+
- [CLI reference](#cli-reference)
|
|
26
|
+
- [Connecting to a running browser](#connecting-to-a-running-browser)
|
|
27
|
+
- [Programmatic usage (AluviaClient)](#programmatic-usage)
|
|
28
|
+
- [Routing rules](#routing-rules)
|
|
29
|
+
- [Block detection and auto-unblocking](#block-detection-and-auto-unblocking)
|
|
30
|
+
- [Tool integration adapters](#tool-integration-adapters)
|
|
31
|
+
- [REST API (AluviaApi)](#rest-api)
|
|
32
|
+
- [Architecture](#architecture)
|
|
17
33
|
|
|
18
34
|
---
|
|
19
35
|
|
|
20
|
-
##
|
|
36
|
+
## Quick start
|
|
21
37
|
|
|
22
|
-
|
|
38
|
+
### 1. Get Aluvia API key
|
|
23
39
|
|
|
24
|
-
|
|
40
|
+
[Aluvia dashboard](https://dashboard.aluvia.io)
|
|
25
41
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
│ │ │ │ │ │
|
|
32
|
-
└──────────────────┘ │ Per-request routing: │ └──────────────────────┘
|
|
33
|
-
│ │
|
|
34
|
-
│ not-blocked.com ──────────────▶ Direct
|
|
35
|
-
│ blocked-site.com ─────────────▶ Via Aluvia
|
|
36
|
-
│ │
|
|
37
|
-
└──────────────────────────┘
|
|
42
|
+
### 2. Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install @aluvia/sdk playwright
|
|
46
|
+
export ALUVIA_API_KEY="your-api-key"
|
|
38
47
|
```
|
|
39
48
|
|
|
49
|
+
### 3. Run
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
- **Avoid blocks:** Websites flag datacenter IPs as bot traffic, leading to 403s, CAPTCHAs, and rate limits. Mobile IPs appear as real users, so requests go through.
|
|
43
|
-
- **Reduce costs and latency:** Hostname-based routing rules let you proxy only the sites that need it. Traffic to non-blocked sites goes direct, saving money and reducing latency.
|
|
44
|
-
- **Unblock without restarts:** Rules update at runtime. When a site blocks your agent, add it to the proxy rules and retry—no need to restart workers or redeploy.
|
|
45
|
-
- **Simplify integration:** One SDK with ready-to-use adapters for Playwright, Puppeteer, Selenium, Axios, got, and Node's fetch.
|
|
51
|
+
Aluvia automatically detects website blocks and uses mobile IPs when necessary.
|
|
46
52
|
|
|
53
|
+
```bash
|
|
54
|
+
aluvia session start https://example.com --auto-unblock --run your-script.js
|
|
55
|
+
```
|
|
47
56
|
|
|
48
57
|
---
|
|
49
58
|
|
|
50
|
-
##
|
|
59
|
+
## Skills
|
|
60
|
+
|
|
61
|
+
- Claude code skll
|
|
62
|
+
- OpenClaw skill
|
|
51
63
|
|
|
52
|
-
|
|
53
|
-
* [What is Aluvia?](https://docs.aluvia.io/)
|
|
54
|
-
* [Understanding connections](https://docs.aluvia.io/fundamentals/connections)
|
|
64
|
+
---
|
|
55
65
|
|
|
56
|
-
|
|
66
|
+
## CLI reference
|
|
57
67
|
|
|
58
|
-
|
|
59
|
-
2. Go to **API and SDKs** and get your **API Key**
|
|
68
|
+
The CLI outputs JSON for easy integration with AI agent frameworks. All commands are available via the `aluvia` binary. Run `aluvia help --json` for machine-readable help.
|
|
60
69
|
|
|
61
|
-
###
|
|
70
|
+
### `session start` — Launch a browser session
|
|
62
71
|
|
|
63
72
|
```bash
|
|
64
|
-
|
|
73
|
+
aluvia session start <url> [options]
|
|
65
74
|
```
|
|
66
75
|
|
|
67
|
-
|
|
76
|
+
| Option | Description |
|
|
77
|
+
| --------------------------- | ------------------------------------------------------------------------ |
|
|
78
|
+
| `--auto-unblock` | Auto-detect blocks and reload through Aluvia |
|
|
79
|
+
| `--run <script>` | Run a script with `page`, `browser`, `context` injected; exits when done |
|
|
80
|
+
| `--headful` | Show the browser window (default: headless) |
|
|
81
|
+
| `--browser-session <name>` | Name this session (auto-generated if omitted, e.g. `swift-falcon`) |
|
|
82
|
+
| `--connection-id <id>` | Reuse an existing Aluvia connection |
|
|
83
|
+
| `--disable-block-detection` | Disable block detection entirely |
|
|
68
84
|
|
|
69
|
-
|
|
85
|
+
**Examples:**
|
|
70
86
|
|
|
71
|
-
|
|
87
|
+
```bash
|
|
88
|
+
# Launch with auto-unblocking
|
|
89
|
+
aluvia session start https://example.com --auto-unblock
|
|
72
90
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
import { AluviaClient } from '@aluvia/sdk';
|
|
91
|
+
# Run a script inline
|
|
92
|
+
aluvia session start https://example.com --auto-unblock --run scrape.mjs
|
|
76
93
|
|
|
77
|
-
|
|
78
|
-
|
|
94
|
+
# Debug with a visible browser window
|
|
95
|
+
aluvia session start https://example.com --headful
|
|
79
96
|
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
# Reuse an existing connection
|
|
98
|
+
aluvia session start https://example.com --connection-id 3449
|
|
99
|
+
```
|
|
82
100
|
|
|
83
|
-
|
|
84
|
-
await client.updateTargetGeo('us_ca');
|
|
101
|
+
### `session close` — Stop a session
|
|
85
102
|
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
```bash
|
|
104
|
+
aluvia session close # auto-selects if only one is running
|
|
105
|
+
aluvia session close --browser-session swift-falcon # close by name
|
|
106
|
+
aluvia session close --all # close all sessions
|
|
107
|
+
```
|
|
88
108
|
|
|
89
|
-
|
|
90
|
-
// The adapter returns proxy settings in Playwright's expected format
|
|
91
|
-
const browser = await chromium.launch({ proxy: connection.asPlaywright() });
|
|
109
|
+
### `session list` — List active sessions
|
|
92
110
|
|
|
93
|
-
|
|
94
|
-
|
|
111
|
+
```bash
|
|
112
|
+
aluvia session list
|
|
113
|
+
```
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"sessions": [
|
|
118
|
+
{
|
|
119
|
+
"browserSession": "swift-falcon",
|
|
120
|
+
"pid": 12345,
|
|
121
|
+
"startUrl": "https://example.com",
|
|
122
|
+
"cdpUrl": "http://127.0.0.1:38209",
|
|
123
|
+
"connectionId": 3449,
|
|
124
|
+
"blockDetection": true,
|
|
125
|
+
"autoUnblock": true
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"count": 1
|
|
129
|
+
}
|
|
130
|
+
```
|
|
98
131
|
|
|
99
|
-
|
|
100
|
-
const response = await page.goto(url, { waitUntil: 'domcontentloaded' });
|
|
101
|
-
const hostname = new URL(url).hostname;
|
|
132
|
+
### `session get` — Full session details
|
|
102
133
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
status === 403 ||
|
|
107
|
-
status === 429 ||
|
|
108
|
-
(await page.title()).toLowerCase().includes('blocked');
|
|
134
|
+
```bash
|
|
135
|
+
aluvia session get [--browser-session <name>]
|
|
136
|
+
```
|
|
109
137
|
|
|
110
|
-
|
|
111
|
-
console.log(`Blocked by ${hostname} — adding to proxy rules`);
|
|
138
|
+
Returns session info enriched with block detection history and the full connection object from the API.
|
|
112
139
|
|
|
113
|
-
|
|
114
|
-
// Rules update at runtime—no need to restart the browser
|
|
115
|
-
proxiedHosts.add(hostname);
|
|
116
|
-
await client.updateRules([...proxiedHosts]);
|
|
140
|
+
### `session rotate-ip` — Get a new IP
|
|
117
141
|
|
|
118
|
-
|
|
119
|
-
|
|
142
|
+
```bash
|
|
143
|
+
aluvia session rotate-ip [--browser-session <name>]
|
|
144
|
+
```
|
|
120
145
|
|
|
121
|
-
|
|
122
|
-
return visitWithRetry(url);
|
|
123
|
-
}
|
|
146
|
+
### `session set-geo` — Target a specific region
|
|
124
147
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
148
|
+
```bash
|
|
149
|
+
aluvia session set-geo US # target US IPs
|
|
150
|
+
aluvia session set-geo us_ca # target California
|
|
151
|
+
aluvia session set-geo --clear # clear geo targeting
|
|
152
|
+
```
|
|
130
153
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
// Always close the browser and connection when done
|
|
137
|
-
await browser.close();
|
|
138
|
-
await connection.close();
|
|
139
|
-
}
|
|
154
|
+
### `session set-rules` — Update routing rules
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
aluvia session set-rules "example.com,api.example.com" # add rules
|
|
158
|
+
aluvia session set-rules --remove "example.com" # remove rules
|
|
140
159
|
```
|
|
141
160
|
|
|
142
|
-
|
|
161
|
+
Rules are comma-separated. By default rules are appended; use `--remove` to remove specific rules.
|
|
143
162
|
|
|
144
|
-
|
|
163
|
+
### Account and other commands
|
|
145
164
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
-
|
|
150
|
-
|
|
151
|
-
|
|
165
|
+
```bash
|
|
166
|
+
aluvia account # account info
|
|
167
|
+
aluvia account usage # usage stats
|
|
168
|
+
aluvia account usage --start 2025-01-01T00:00:00Z --end 2025-02-01T00:00:00Z
|
|
169
|
+
|
|
170
|
+
aluvia geos # list available geo-targeting options
|
|
171
|
+
aluvia help # plain text help
|
|
172
|
+
aluvia help --json # machine-readable help
|
|
173
|
+
```
|
|
152
174
|
|
|
153
175
|
---
|
|
154
176
|
|
|
177
|
+
## Connecting to a running browser
|
|
155
178
|
|
|
179
|
+
There are two ways to run code against a browser session started by the CLI.
|
|
156
180
|
|
|
157
|
-
|
|
181
|
+
### Option A: `--run` (simplest)
|
|
158
182
|
|
|
159
|
-
The
|
|
183
|
+
Pass a script to `session start`. The globals `page`, `browser`, and `context` are available — no imports needed:
|
|
160
184
|
|
|
185
|
+
```bash
|
|
186
|
+
aluvia session start https://example.com --auto-unblock --run script.mjs
|
|
161
187
|
```
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
│ • PATCH updates (rules, │ • Uses rules engine to decide: │
|
|
171
|
-
│ session, geo) │ direct vs gateway │
|
|
172
|
-
└─────────────────────────────┴───────────────────────────────────┘
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
// script.mjs
|
|
191
|
+
console.log("URL:", page.url());
|
|
192
|
+
|
|
193
|
+
const newPage = await context.newPage();
|
|
194
|
+
await newPage.goto("https://another-site.com");
|
|
195
|
+
console.log("Other site title:", await newPage.title());
|
|
173
196
|
```
|
|
174
197
|
|
|
175
|
-
|
|
198
|
+
The session starts, runs your script, and exits.
|
|
176
199
|
|
|
177
|
-
|
|
178
|
-
- Fetches proxy credentials and routing rules
|
|
179
|
-
- Polls for configuration updates
|
|
180
|
-
- Pushes updates (rules, session ID, geo)
|
|
200
|
+
### Option B: `connect()` (for AI agents and long-running processes)
|
|
181
201
|
|
|
182
|
-
|
|
202
|
+
Start a session as a background daemon, then connect from your application:
|
|
183
203
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
204
|
+
```bash
|
|
205
|
+
aluvia session start https://example.com --auto-unblock
|
|
206
|
+
```
|
|
187
207
|
|
|
188
|
-
|
|
208
|
+
```ts
|
|
209
|
+
import { connect } from "@aluvia/sdk";
|
|
189
210
|
|
|
190
|
-
|
|
211
|
+
// Auto-discovers the running session
|
|
212
|
+
const { page, browser, context, disconnect } = await connect();
|
|
213
|
+
console.log("URL:", page.url());
|
|
191
214
|
|
|
192
|
-
|
|
215
|
+
// When running multiple sessions, specify by name
|
|
216
|
+
const conn = await connect("swift-falcon");
|
|
217
|
+
console.log("URL:", conn.page.url());
|
|
193
218
|
|
|
194
|
-
|
|
219
|
+
// Disconnect when done (the session keeps running)
|
|
220
|
+
await disconnect();
|
|
221
|
+
```
|
|
195
222
|
|
|
196
|
-
|
|
223
|
+
Use this when your agent generates automation code dynamically at runtime or needs a persistent browser across multiple operations.
|
|
197
224
|
|
|
198
|
-
|
|
199
|
-
- Selective routing reduces cost and latency (only proxy what you need)
|
|
200
|
-
- Credentials stay inside the SDK (nothing secret in your config)
|
|
201
|
-
- Rule changes apply immediately (no restarts)
|
|
225
|
+
---
|
|
202
226
|
|
|
203
|
-
|
|
227
|
+
## Programmatic usage
|
|
204
228
|
|
|
205
|
-
|
|
229
|
+
For full control, use `AluviaClient` directly instead of the CLI.
|
|
206
230
|
|
|
207
|
-
|
|
231
|
+
### Basic example
|
|
208
232
|
|
|
209
|
-
|
|
233
|
+
```ts
|
|
234
|
+
import { AluviaClient } from "@aluvia/sdk";
|
|
235
|
+
import { chromium } from "playwright";
|
|
210
236
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
237
|
+
const client = new AluviaClient({
|
|
238
|
+
apiKey: process.env.ALUVIA_API_KEY!,
|
|
239
|
+
});
|
|
214
240
|
|
|
215
|
-
|
|
241
|
+
const connection = await client.start();
|
|
242
|
+
const browser = await chromium.launch({ proxy: connection.asPlaywright() });
|
|
243
|
+
const page = await browser.newPage();
|
|
244
|
+
await page.goto("https://example.com");
|
|
216
245
|
|
|
217
|
-
|
|
246
|
+
// ... do your work ...
|
|
218
247
|
|
|
219
|
-
|
|
248
|
+
await browser.close();
|
|
249
|
+
await connection.close();
|
|
250
|
+
```
|
|
220
251
|
|
|
221
|
-
###
|
|
252
|
+
### With auto-launched browser
|
|
222
253
|
|
|
223
254
|
```ts
|
|
224
255
|
const client = new AluviaClient({
|
|
225
256
|
apiKey: process.env.ALUVIA_API_KEY!,
|
|
226
|
-
|
|
227
|
-
|
|
257
|
+
startPlaywright: true,
|
|
258
|
+
blockDetection: {
|
|
259
|
+
enabled: true,
|
|
260
|
+
autoUnblock: true,
|
|
261
|
+
},
|
|
228
262
|
});
|
|
263
|
+
|
|
264
|
+
const connection = await client.start();
|
|
265
|
+
const page = await connection.browser.newPage();
|
|
266
|
+
await page.goto("https://example.com"); // auto-reloads through Aluvia if blocked
|
|
267
|
+
|
|
268
|
+
await connection.close(); // stops proxy, closes browser, releases resources
|
|
229
269
|
```
|
|
230
270
|
|
|
231
|
-
|
|
271
|
+
### Runtime updates
|
|
232
272
|
|
|
233
|
-
|
|
273
|
+
While your agent is running, update routing, rotate IPs, or change geo — no restarts needed:
|
|
234
274
|
|
|
235
275
|
```ts
|
|
236
|
-
|
|
276
|
+
await client.updateRules(["blocked-site.com"]); // proxy this hostname
|
|
277
|
+
await client.updateSessionId("new-session-id"); // rotate to a new IP
|
|
278
|
+
await client.updateTargetGeo("us_ca"); // target California IPs
|
|
237
279
|
```
|
|
238
280
|
|
|
239
|
-
|
|
240
|
-
[Understanding the connection object](https://docs.aluvia.io/fundamentals/connections)
|
|
241
|
-
|
|
242
|
-
### 3. Use the connection with your tools
|
|
243
|
-
|
|
244
|
-
Pass the connection to your automation tool using the appropriate adapter:
|
|
281
|
+
### Constructor options
|
|
245
282
|
|
|
246
283
|
```ts
|
|
247
|
-
|
|
284
|
+
new AluviaClient({
|
|
285
|
+
apiKey: string; // Required
|
|
286
|
+
connectionId?: number; // Reuse an existing connection
|
|
287
|
+
startPlaywright?: boolean; // Auto-launch Chromium browser
|
|
288
|
+
headless?: boolean; // Default: true (only with startPlaywright)
|
|
289
|
+
blockDetection?: BlockDetectionConfig; // See "Block detection" section
|
|
290
|
+
localPort?: number; // Local proxy port (auto-assigned if omitted)
|
|
291
|
+
gatewayProtocol?: "http" | "https"; // Default: "http"
|
|
292
|
+
gatewayPort?: number; // Default: 8080 (http) or 8443 (https)
|
|
293
|
+
pollIntervalMs?: number; // Config poll interval (default: 5000ms)
|
|
294
|
+
timeoutMs?: number; // API request timeout
|
|
295
|
+
logLevel?: "silent" | "info" | "debug";
|
|
296
|
+
strict?: boolean; // Throw if config fails to load (default: true)
|
|
297
|
+
apiBaseUrl?: string; // Default: "https://api.aluvia.io/v1"
|
|
298
|
+
});
|
|
248
299
|
```
|
|
249
300
|
|
|
250
|
-
|
|
301
|
+
For all options in detail, see the [Client Technical Guide](docs/client-technical-guide.md#constructor-options).
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Routing rules
|
|
306
|
+
|
|
307
|
+
The local proxy routes each request based on hostname rules. Only hostnames matching a rule go through Aluvia; everything else goes direct.
|
|
251
308
|
|
|
252
|
-
|
|
309
|
+
### Why this matters
|
|
310
|
+
|
|
311
|
+
- **Save money** — proxy only the sites that block you
|
|
312
|
+
- **Lower latency** — non-blocked sites skip the proxy entirely
|
|
313
|
+
- **Adapt on the fly** — rules update at runtime, no restarts needed
|
|
314
|
+
|
|
315
|
+
### Rule patterns
|
|
316
|
+
|
|
317
|
+
| Pattern | Matches |
|
|
318
|
+
| --------------- | ------------------------------ |
|
|
319
|
+
| `*` | All hostnames |
|
|
320
|
+
| `example.com` | Exact match |
|
|
321
|
+
| `*.example.com` | Subdomains of example.com |
|
|
322
|
+
| `google.*` | google.com, google.co.uk, etc. |
|
|
323
|
+
| `-example.com` | Exclude from proxying |
|
|
324
|
+
|
|
325
|
+
### Examples
|
|
253
326
|
|
|
254
327
|
```ts
|
|
255
|
-
|
|
256
|
-
await client.
|
|
257
|
-
|
|
328
|
+
// Proxy all traffic
|
|
329
|
+
await client.updateRules(["*"]);
|
|
330
|
+
|
|
331
|
+
// Proxy specific hosts only
|
|
332
|
+
await client.updateRules(["target-site.com", "*.google.com"]);
|
|
333
|
+
|
|
334
|
+
// Proxy everything except Stripe
|
|
335
|
+
await client.updateRules(["*", "-api.stripe.com"]);
|
|
336
|
+
|
|
337
|
+
// Route all traffic direct (no proxy)
|
|
338
|
+
await client.updateRules([]);
|
|
258
339
|
```
|
|
259
340
|
|
|
260
|
-
|
|
341
|
+
Or from the CLI:
|
|
261
342
|
|
|
262
|
-
```
|
|
263
|
-
|
|
343
|
+
```bash
|
|
344
|
+
aluvia session set-rules "target-site.com,*.google.com"
|
|
345
|
+
aluvia session set-rules --remove "target-site.com"
|
|
264
346
|
```
|
|
265
347
|
|
|
266
348
|
---
|
|
267
349
|
|
|
268
|
-
##
|
|
350
|
+
## Block detection and auto-unblocking
|
|
269
351
|
|
|
270
|
-
|
|
352
|
+
Most proxy solutions require you to decide upfront which sites to proxy. If a site blocks you later, you're stuck.
|
|
353
|
+
|
|
354
|
+
Aluvia detects blocks automatically and can unblock your agent on the fly. The SDK analyzes every page load using a weighted scoring system across multiple signals — HTTP status codes, WAF headers, CAPTCHA selectors, page content, redirect chains, and more.
|
|
355
|
+
|
|
356
|
+
### Automatic unblocking (recommended)
|
|
357
|
+
|
|
358
|
+
When a block is detected, the SDK adds the hostname to proxy rules and reloads the page through Aluvia:
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
const client = new AluviaClient({
|
|
362
|
+
apiKey: process.env.ALUVIA_API_KEY!,
|
|
363
|
+
startPlaywright: true,
|
|
364
|
+
blockDetection: {
|
|
365
|
+
enabled: true,
|
|
366
|
+
autoUnblock: true,
|
|
367
|
+
onDetection: (result, page) => {
|
|
368
|
+
console.log(
|
|
369
|
+
`${result.blockStatus} on ${result.hostname} (score: ${result.score})`,
|
|
370
|
+
);
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
```
|
|
271
375
|
|
|
272
|
-
|
|
273
|
-
* direct (using the agent's datacenter/cloud IP) or,
|
|
274
|
-
* through Aluvia's mobile proxy IPs,
|
|
376
|
+
Or from the CLI:
|
|
275
377
|
|
|
276
|
-
|
|
378
|
+
```bash
|
|
379
|
+
aluvia session start https://example.com --auto-unblock
|
|
380
|
+
```
|
|
277
381
|
|
|
278
|
-
|
|
279
|
-
* Rules can be updated during runtime, allowing agents to work around website blocks on the fly.
|
|
382
|
+
### Detection-only mode
|
|
280
383
|
|
|
281
|
-
|
|
384
|
+
Run detection without automatic remediation. Your agent inspects the results and decides what to do:
|
|
282
385
|
|
|
283
386
|
```ts
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
387
|
+
blockDetection: {
|
|
388
|
+
enabled: true,
|
|
389
|
+
onDetection: (result, page) => {
|
|
390
|
+
if (result.blockStatus === "blocked") {
|
|
391
|
+
// Agent decides: retry, rotate IP, update rules, etc.
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
}
|
|
288
395
|
```
|
|
289
396
|
|
|
290
|
-
###
|
|
397
|
+
### Block status scores
|
|
291
398
|
|
|
292
|
-
|
|
293
|
-
|---------|---------|
|
|
294
|
-
| `*` | All hostnames |
|
|
295
|
-
| `example.com` | Exact match |
|
|
296
|
-
| `*.example.com` | Subdomains of example.com |
|
|
297
|
-
| `google.*` | google.com, google.co.uk, and similar |
|
|
298
|
-
| `-example.com` | Exclude from proxying |
|
|
399
|
+
Each page analysis produces a score from 0.0 to 1.0:
|
|
299
400
|
|
|
300
|
-
|
|
401
|
+
| Score | Status | Meaning |
|
|
402
|
+
| ------ | ------------- | --------------------------------------------------------------- |
|
|
403
|
+
| >= 0.7 | `"blocked"` | High confidence block. Auto-reloads when `autoUnblock: true`. |
|
|
404
|
+
| >= 0.4 | `"suspected"` | Possible block. Reloads only if `autoUnblockOnSuspected: true`. |
|
|
405
|
+
| < 0.4 | `"clear"` | No block detected. |
|
|
406
|
+
|
|
407
|
+
Scores use probabilistic combination (`1 - product(1 - weight)`) so weak signals don't stack into false positives.
|
|
408
|
+
|
|
409
|
+
### How detection works
|
|
301
410
|
|
|
302
|
-
|
|
411
|
+
Detection runs in two passes:
|
|
303
412
|
|
|
304
|
-
|
|
413
|
+
1. **Fast pass** (at `domcontentloaded`) — checks HTTP status codes and WAF response headers. High-confidence blocks (score >= 0.9) trigger immediate remediation.
|
|
414
|
+
2. **Full pass** (after `networkidle`) — analyzes page title, visible text, challenge selectors, meta refreshes, and redirect chains.
|
|
305
415
|
|
|
306
|
-
|
|
416
|
+
The SDK also detects SPA navigations and tracks persistent blocks per hostname to prevent infinite retry loops.
|
|
307
417
|
|
|
308
|
-
|
|
418
|
+
### Detection config options
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
blockDetection: {
|
|
422
|
+
enabled?: boolean; // Default: true
|
|
423
|
+
autoUnblock?: boolean; // Auto-remediate blocked pages
|
|
424
|
+
autoUnblockOnSuspected?: boolean; // Also remediate "suspected" pages
|
|
425
|
+
challengeSelectors?: string[]; // Custom CSS selectors for challenge detection
|
|
426
|
+
extraKeywords?: string[]; // Additional keywords for text analysis
|
|
427
|
+
extraStatusCodes?: number[]; // Additional HTTP status codes to flag
|
|
428
|
+
networkIdleTimeoutMs?: number; // Default: 3000ms
|
|
429
|
+
onDetection?: (result, page) => void | Promise<void>;
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Manual detection
|
|
434
|
+
|
|
435
|
+
You can also check responses yourself and update rules on the fly:
|
|
309
436
|
|
|
310
437
|
```ts
|
|
311
438
|
const response = await page.goto(url);
|
|
312
439
|
|
|
313
440
|
if (response?.status() === 403) {
|
|
314
|
-
// Blocked! Add this hostname to proxy rules and retry
|
|
315
441
|
await client.updateRules([...currentRules, new URL(url).hostname]);
|
|
316
|
-
await page.goto(url);
|
|
442
|
+
await page.goto(url); // retried through Aluvia
|
|
317
443
|
}
|
|
318
444
|
```
|
|
319
445
|
|
|
320
|
-
|
|
446
|
+
For the full list of signal detectors and weights, see the [Client Technical Guide](docs/client-technical-guide.md#signal-detectors).
|
|
321
447
|
|
|
322
448
|
---
|
|
323
449
|
|
|
324
450
|
## Tool integration adapters
|
|
325
451
|
|
|
326
|
-
|
|
452
|
+
The SDK handles proxy configuration for every major tool:
|
|
453
|
+
|
|
454
|
+
| Tool | Method | Returns |
|
|
455
|
+
| ------------ | ---------------------------- | ----------------------------------------------------- |
|
|
456
|
+
| Playwright | `connection.asPlaywright()` | `{ server, username?, password? }` |
|
|
457
|
+
| Playwright | `connection.browser` | Auto-launched Chromium (with `startPlaywright: true`) |
|
|
458
|
+
| Playwright | `connection.cdpUrl` | CDP endpoint for `connectOverCDP()` |
|
|
459
|
+
| Puppeteer | `connection.asPuppeteer()` | `['--proxy-server=...']` |
|
|
460
|
+
| Selenium | `connection.asSelenium()` | `'--proxy-server=...'` |
|
|
461
|
+
| Axios | `connection.asAxiosConfig()` | `{ proxy: false, httpAgent, httpsAgent }` |
|
|
462
|
+
| got | `connection.asGotOptions()` | `{ agent: { http, https } }` |
|
|
463
|
+
| fetch | `connection.asUndiciFetch()` | Proxy-enabled `fetch` function |
|
|
464
|
+
| Node.js http | `connection.asNodeAgents()` | `{ http: Agent, https: Agent }` |
|
|
465
|
+
|
|
466
|
+
### Examples
|
|
467
|
+
|
|
468
|
+
```ts
|
|
469
|
+
// Playwright
|
|
470
|
+
const browser = await chromium.launch({ proxy: connection.asPlaywright() });
|
|
471
|
+
|
|
472
|
+
// Puppeteer
|
|
473
|
+
const browser = await puppeteer.launch({ args: connection.asPuppeteer() });
|
|
327
474
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
| Puppeteer | `connection.asPuppeteer()` | `['--proxy-server=...']` |
|
|
332
|
-
| Selenium | `connection.asSelenium()` | `'--proxy-server=...'` |
|
|
333
|
-
| Axios | `connection.asAxiosConfig()` | `{ proxy: false, httpAgent, httpsAgent }` |
|
|
334
|
-
| got | `connection.asGotOptions()` | `{ agent: { http, https } }` |
|
|
335
|
-
| fetch | `connection.asUndiciFetch()` | Proxy-enabled `fetch` function |
|
|
336
|
-
| Node.js http | `connection.asNodeAgents()` | `{ http: Agent, https: Agent }` |
|
|
475
|
+
// Axios
|
|
476
|
+
const axiosClient = axios.create(connection.asAxiosConfig());
|
|
477
|
+
await axiosClient.get("https://example.com");
|
|
337
478
|
|
|
338
|
-
|
|
479
|
+
// got
|
|
480
|
+
const gotClient = got.extend(connection.asGotOptions());
|
|
481
|
+
await gotClient("https://example.com");
|
|
339
482
|
|
|
483
|
+
// Node's fetch (via undici)
|
|
484
|
+
const myFetch = connection.asUndiciFetch();
|
|
485
|
+
await myFetch("https://example.com");
|
|
486
|
+
```
|
|
340
487
|
|
|
488
|
+
For more details, see the [Client Technical Guide](docs/client-technical-guide.md#tool-adapters).
|
|
341
489
|
|
|
342
490
|
---
|
|
343
491
|
|
|
344
|
-
##
|
|
345
|
-
|
|
346
|
-
`AluviaApi` is a typed wrapper for the Aluvia REST API. Use it to manage connections,
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|
361
|
-
│ │ │ │ │
|
|
362
|
-
│ ▼ ▼ ▼ │
|
|
363
|
-
│ ┌────────────────────────────────────────────────────┐ │
|
|
364
|
-
│ │ requestAndUnwrap / ctx.request │ │
|
|
365
|
-
│ │ (envelope unwrapping, error throwing) │ │
|
|
366
|
-
│ └────────────────────────────────────────────────────┘ │
|
|
367
|
-
│ │ │
|
|
368
|
-
│ ▼ │
|
|
369
|
-
│ ┌────────────────────────────────────────────────────┐ │
|
|
370
|
-
│ │ requestCore │ │
|
|
371
|
-
│ │ (URL building, headers, timeout, JSON parsing) │ │
|
|
372
|
-
│ └────────────────────────────────────────────────────┘ │
|
|
373
|
-
│ │ │
|
|
374
|
-
│ ▼ │
|
|
375
|
-
│ globalThis.fetch │
|
|
376
|
-
└───────────────────────────────────────────────────────────────┘
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
### What you can do
|
|
380
|
-
|
|
381
|
-
| Endpoint | Description |
|
|
382
|
-
|----------|-------------|
|
|
383
|
-
| `api.account.get()` | Get account info (balance, usage) |
|
|
384
|
-
| `api.account.connections.list()` | List all connections |
|
|
385
|
-
| `api.account.connections.create()` | Create a new connection |
|
|
386
|
-
| `api.account.connections.get(id)` | Get connection details |
|
|
387
|
-
| `api.account.connections.patch(id)` | Update connection (rules, geo, session) |
|
|
388
|
-
| `api.account.connections.delete(id)` | Delete a connection |
|
|
389
|
-
| `api.geos.list()` | List available geo-targeting options |
|
|
492
|
+
## REST API
|
|
493
|
+
|
|
494
|
+
`AluviaApi` is a typed wrapper for the Aluvia REST API. Use it to manage connections, check account info, or build custom tooling — without starting a proxy.
|
|
495
|
+
|
|
496
|
+
### Endpoints
|
|
497
|
+
|
|
498
|
+
| Method | Description |
|
|
499
|
+
| ----------------------------------------- | --------------------------------------- |
|
|
500
|
+
| `api.account.get()` | Get account info (balance, usage) |
|
|
501
|
+
| `api.account.connections.list()` | List all connections |
|
|
502
|
+
| `api.account.connections.create(body)` | Create a new connection |
|
|
503
|
+
| `api.account.connections.get(id)` | Get connection details |
|
|
504
|
+
| `api.account.connections.patch(id, body)` | Update connection (rules, geo, session) |
|
|
505
|
+
| `api.account.connections.delete(id)` | Delete a connection |
|
|
506
|
+
| `api.account.usage.get(params?)` | Get usage stats |
|
|
507
|
+
| `api.geos.list()` | List available geo-targeting options |
|
|
390
508
|
|
|
391
509
|
### Example
|
|
392
510
|
|
|
393
511
|
```ts
|
|
394
|
-
import { AluviaApi } from
|
|
512
|
+
import { AluviaApi } from "@aluvia/sdk";
|
|
395
513
|
|
|
396
514
|
const api = new AluviaApi({ apiKey: process.env.ALUVIA_API_KEY! });
|
|
397
515
|
|
|
398
516
|
// Check account balance
|
|
399
517
|
const account = await api.account.get();
|
|
400
|
-
console.log(
|
|
518
|
+
console.log("Balance:", account.balance_gb, "GB");
|
|
401
519
|
|
|
402
520
|
// Create a connection for a new agent
|
|
403
|
-
const
|
|
404
|
-
description:
|
|
405
|
-
rules: [
|
|
406
|
-
target_geo:
|
|
521
|
+
const conn = await api.account.connections.create({
|
|
522
|
+
description: "pricing-scraper",
|
|
523
|
+
rules: ["competitor-site.com"],
|
|
524
|
+
target_geo: "us_ca",
|
|
407
525
|
});
|
|
408
|
-
console.log(
|
|
526
|
+
console.log("Created connection:", conn.connection_id);
|
|
409
527
|
|
|
410
528
|
// List available geos
|
|
411
529
|
const geos = await api.geos.list();
|
|
412
|
-
console.log(
|
|
530
|
+
console.log(
|
|
531
|
+
"Geos:",
|
|
532
|
+
geos.map((g) => g.code),
|
|
533
|
+
);
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
`AluviaApi` is also available as `client.api` when using `AluviaClient`.
|
|
537
|
+
|
|
538
|
+
For the complete API reference, see the [API Technical Guide](docs/api-technical-guide.md).
|
|
539
|
+
|
|
540
|
+
---
|
|
541
|
+
|
|
542
|
+
## Architecture
|
|
543
|
+
|
|
544
|
+
The client is split into two independent planes:
|
|
545
|
+
|
|
546
|
+
```
|
|
547
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
548
|
+
│ AluviaClient │
|
|
549
|
+
├─────────────────────────────┬───────────────────────────────────┤
|
|
550
|
+
│ Control Plane │ Data Plane │
|
|
551
|
+
│ (ConfigManager) │ (ProxyServer) │
|
|
552
|
+
├─────────────────────────────┼───────────────────────────────────┤
|
|
553
|
+
│ • Fetches/creates config │ • Local HTTP proxy (proxy-chain) │
|
|
554
|
+
│ • Polls for updates (ETag) │ • Per-request routing decisions │
|
|
555
|
+
│ • PATCH updates (rules, │ • Uses rules engine to decide: │
|
|
556
|
+
│ session, geo) │ direct vs gateway │
|
|
557
|
+
└─────────────────────────────┴───────────────────────────────────┘
|
|
413
558
|
```
|
|
414
559
|
|
|
415
|
-
**
|
|
560
|
+
**Control Plane (ConfigManager)** — communicates with the Aluvia REST API to fetch proxy credentials and routing rules, polls for configuration updates using ETags, and pushes updates (rules, session ID, geo).
|
|
416
561
|
|
|
417
|
-
|
|
562
|
+
**Data Plane (ProxyServer)** — runs a local HTTP proxy on `127.0.0.1` that reads the latest config per-request, so rule updates take effect immediately without restarts.
|
|
563
|
+
|
|
564
|
+
```
|
|
565
|
+
┌──────────────────┐ ┌──────────────────────────┐ ┌──────────────────────┐
|
|
566
|
+
│ │ │ │ │ │
|
|
567
|
+
│ Your Agent │─────▶│ Aluvia Client │─────▶│ gateway.aluvia.io │
|
|
568
|
+
│ │ │ 127.0.0.1:port │ │ (Mobile IPs) │
|
|
569
|
+
│ │ │ │ │ │
|
|
570
|
+
└──────────────────┘ │ Per-request routing: │ └──────────────────────┘
|
|
571
|
+
│ │
|
|
572
|
+
│ not-blocked.com ──────────────▶ Direct
|
|
573
|
+
│ blocked-site.com ─────────────▶ Via Aluvia
|
|
574
|
+
│ │
|
|
575
|
+
└──────────────────────────┘
|
|
576
|
+
```
|
|
418
577
|
|
|
419
578
|
---
|
|
420
579
|
|
|
580
|
+
## Learn more
|
|
581
|
+
|
|
582
|
+
- [What is Aluvia?](https://docs.aluvia.io/)
|
|
583
|
+
- [Understanding connections](https://docs.aluvia.io/fundamentals/connections)
|
|
584
|
+
- [Playwright integration guide](https://docs.aluvia.io/integrations/integration-playwright)
|
|
585
|
+
- [Puppeteer](https://docs.aluvia.io/integrations/integration-puppeteer), [Selenium](https://docs.aluvia.io/integrations/integration-selenium), [Axios](https://docs.aluvia.io/integrations/integration-axios), [got](https://docs.aluvia.io/integrations/integration-got), [fetch](https://docs.aluvia.io/integrations/integration-fetch)
|
|
586
|
+
- [CLI Technical Guide](docs/cli-technical-guide.md)
|
|
587
|
+
- [Client Technical Guide](docs/client-technical-guide.md)
|
|
588
|
+
- [API Technical Guide](docs/api-technical-guide.md)
|
|
589
|
+
|
|
421
590
|
## License
|
|
422
591
|
|
|
423
592
|
MIT — see [LICENSE](./LICENSE)
|