@aluvia/sdk 1.1.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 +409 -285
- 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 +365 -189
- 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 +371 -195
- 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 +48 -47
- 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 -10
package/README.md
CHANGED
|
@@ -5,430 +5,506 @@
|
|
|
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
|
-
**
|
|
13
|
-
|
|
14
|
-
**
|
|
15
|
-
|
|
16
|
-
|
|
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`
|
|
17
19
|
|
|
18
20
|
---
|
|
19
21
|
|
|
20
|
-
##
|
|
21
|
-
|
|
22
|
-
The Aluvia client runs a local rules-based proxy server on your agent's host, handles authentication and connection management, and provides ready-to-use adapters for popular tools like Playwright, Puppeteer, and Axios.
|
|
23
|
-
|
|
24
|
-
Simply point your automation tool at the local proxy address (`127.0.0.1`) and the client handles the rest. For each request, the client checks the destination hostname against user-defined (or agent-defined) routing rules and decides whether to send it through Aluvia's mobile IPs or direct to the destination.
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
┌──────────────────┐ ┌──────────────────────────┐ ┌──────────────────────┐
|
|
28
|
-
│ │ │ │ │ │
|
|
29
|
-
│ Your Agent │─────▶ Aluvia Client ─────▶ gateway.aluvia.io │
|
|
30
|
-
│ │ │ 127.0.0.1:port │ │ (Mobile IPs) │
|
|
31
|
-
│ │ │ │ │ │
|
|
32
|
-
└──────────────────┘ │ Per-request routing: │ └──────────────────────┘
|
|
33
|
-
│ │
|
|
34
|
-
│ not-blocked.com ──────────────▶ Direct
|
|
35
|
-
│ blocked-site.com ─────────────▶ Via Aluvia
|
|
36
|
-
│ │
|
|
37
|
-
└──────────────────────────┘
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**Benefits:**
|
|
22
|
+
## Table of contents
|
|
41
23
|
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
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)
|
|
46
33
|
|
|
47
34
|
---
|
|
48
35
|
|
|
49
36
|
## Quick start
|
|
50
37
|
|
|
51
|
-
###
|
|
38
|
+
### 1. Get Aluvia API key
|
|
52
39
|
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
[Aluvia dashboard](https://dashboard.aluvia.io)
|
|
41
|
+
|
|
42
|
+
### 2. Install
|
|
55
43
|
|
|
56
|
-
|
|
44
|
+
```bash
|
|
45
|
+
npm install @aluvia/sdk playwright
|
|
46
|
+
export ALUVIA_API_KEY="your-api-key"
|
|
47
|
+
```
|
|
57
48
|
|
|
58
|
-
|
|
59
|
-
2. Go to **API and SDKs** and get your **API Key**
|
|
49
|
+
### 3. Run
|
|
60
50
|
|
|
61
|
-
|
|
51
|
+
Aluvia automatically detects website blocks and uses mobile IPs when necessary.
|
|
62
52
|
|
|
63
53
|
```bash
|
|
64
|
-
|
|
54
|
+
aluvia session start https://example.com --auto-unblock --run your-script.js
|
|
65
55
|
```
|
|
66
56
|
|
|
67
|
-
|
|
57
|
+
---
|
|
68
58
|
|
|
69
|
-
|
|
59
|
+
## Skills
|
|
70
60
|
|
|
71
|
-
|
|
61
|
+
- Claude code skll
|
|
62
|
+
- OpenClaw skill
|
|
72
63
|
|
|
73
|
-
|
|
74
|
-
import { chromium } from "playwright";
|
|
75
|
-
import { AluviaClient } from "@aluvia/sdk";
|
|
64
|
+
---
|
|
76
65
|
|
|
77
|
-
|
|
78
|
-
const client = new AluviaClient({ apiKey: process.env.ALUVIA_API_KEY! });
|
|
66
|
+
## CLI reference
|
|
79
67
|
|
|
80
|
-
|
|
81
|
-
const connection = await client.start();
|
|
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.
|
|
82
69
|
|
|
83
|
-
|
|
84
|
-
await client.updateTargetGeo("us_ca");
|
|
70
|
+
### `session start` — Launch a browser session
|
|
85
71
|
|
|
86
|
-
|
|
87
|
-
|
|
72
|
+
```bash
|
|
73
|
+
aluvia session start <url> [options]
|
|
74
|
+
```
|
|
88
75
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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 |
|
|
92
84
|
|
|
93
|
-
|
|
94
|
-
const proxiedHosts = new Set<string>();
|
|
85
|
+
**Examples:**
|
|
95
86
|
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
```bash
|
|
88
|
+
# Launch with auto-unblocking
|
|
89
|
+
aluvia session start https://example.com --auto-unblock
|
|
98
90
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const hostname = new URL(url).hostname;
|
|
91
|
+
# Run a script inline
|
|
92
|
+
aluvia session start https://example.com --auto-unblock --run scrape.mjs
|
|
102
93
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const isBlocked =
|
|
106
|
-
status === 403 ||
|
|
107
|
-
status === 429 ||
|
|
108
|
-
(await page.title()).toLowerCase().includes("blocked");
|
|
94
|
+
# Debug with a visible browser window
|
|
95
|
+
aluvia session start https://example.com --headful
|
|
109
96
|
|
|
110
|
-
|
|
111
|
-
|
|
97
|
+
# Reuse an existing connection
|
|
98
|
+
aluvia session start https://example.com --connection-id 3449
|
|
99
|
+
```
|
|
112
100
|
|
|
113
|
-
|
|
114
|
-
// Rules update at runtime—no need to restart the browser
|
|
115
|
-
proxiedHosts.add(hostname);
|
|
116
|
-
await client.updateRules([...proxiedHosts]);
|
|
101
|
+
### `session close` — Stop a session
|
|
117
102
|
|
|
118
|
-
|
|
119
|
-
|
|
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
|
+
```
|
|
120
108
|
|
|
121
|
-
|
|
122
|
-
return visitWithRetry(url);
|
|
123
|
-
}
|
|
109
|
+
### `session list` — List active sessions
|
|
124
110
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
}
|
|
111
|
+
```bash
|
|
112
|
+
aluvia session list
|
|
113
|
+
```
|
|
130
114
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
|
139
129
|
}
|
|
140
130
|
```
|
|
141
131
|
|
|
142
|
-
###
|
|
143
|
-
|
|
144
|
-
For even simpler setup, the SDK can automatically launch a Chromium browser that's already configured with the Aluvia proxy. This eliminates the need to manually import Playwright and configure proxy settings.
|
|
132
|
+
### `session get` — Full session details
|
|
145
133
|
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// Initialize with startPlaywright option to auto-launch browser
|
|
150
|
-
const client = new AluviaClient({
|
|
151
|
-
apiKey: process.env.ALUVIA_API_KEY!,
|
|
152
|
-
startPlaywright: true, // Automatically launch and configure Chromium
|
|
153
|
-
});
|
|
134
|
+
```bash
|
|
135
|
+
aluvia session get [--browser-session <name>]
|
|
136
|
+
```
|
|
154
137
|
|
|
155
|
-
|
|
156
|
-
const connection = await client.start();
|
|
138
|
+
Returns session info enriched with block detection history and the full connection object from the API.
|
|
157
139
|
|
|
158
|
-
|
|
159
|
-
const browser = connection.browser;
|
|
160
|
-
const page = await browser.newPage();
|
|
140
|
+
### `session rotate-ip` — Get a new IP
|
|
161
141
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
142
|
+
```bash
|
|
143
|
+
aluvia session rotate-ip [--browser-session <name>]
|
|
144
|
+
```
|
|
165
145
|
|
|
166
|
-
|
|
167
|
-
await page.goto("https://example.com");
|
|
168
|
-
console.log("Title:", await page.title());
|
|
146
|
+
### `session set-geo` — Target a specific region
|
|
169
147
|
|
|
170
|
-
|
|
171
|
-
|
|
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
|
|
172
152
|
```
|
|
173
153
|
|
|
174
|
-
|
|
154
|
+
### `session set-rules` — Update routing rules
|
|
175
155
|
|
|
176
156
|
```bash
|
|
177
|
-
|
|
178
|
-
|
|
157
|
+
aluvia session set-rules "example.com,api.example.com" # add rules
|
|
158
|
+
aluvia session set-rules --remove "example.com" # remove rules
|
|
179
159
|
```
|
|
180
160
|
|
|
181
|
-
|
|
161
|
+
Rules are comma-separated. By default rules are appended; use `--remove` to remove specific rules.
|
|
182
162
|
|
|
183
|
-
|
|
163
|
+
### Account and other commands
|
|
184
164
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
+
```
|
|
191
174
|
|
|
192
175
|
---
|
|
193
176
|
|
|
194
|
-
##
|
|
177
|
+
## Connecting to a running browser
|
|
195
178
|
|
|
196
|
-
|
|
179
|
+
There are two ways to run code against a browser session started by the CLI.
|
|
197
180
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
├─────────────────────────────┼───────────────────────────────────┤
|
|
205
|
-
│ • Fetches/creates config │ • Local HTTP proxy (proxy-chain) │
|
|
206
|
-
│ • Polls for updates (ETag) │ • Per-request routing decisions │
|
|
207
|
-
│ • PATCH updates (rules, │ • Uses rules engine to decide: │
|
|
208
|
-
│ session, geo) │ direct vs gateway │
|
|
209
|
-
└─────────────────────────────┴───────────────────────────────────┘
|
|
181
|
+
### Option A: `--run` (simplest)
|
|
182
|
+
|
|
183
|
+
Pass a script to `session start`. The globals `page`, `browser`, and `context` are available — no imports needed:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
aluvia session start https://example.com --auto-unblock --run script.mjs
|
|
210
187
|
```
|
|
211
188
|
|
|
212
|
-
|
|
189
|
+
```js
|
|
190
|
+
// script.mjs
|
|
191
|
+
console.log("URL:", page.url());
|
|
213
192
|
|
|
214
|
-
|
|
215
|
-
-
|
|
216
|
-
|
|
217
|
-
|
|
193
|
+
const newPage = await context.newPage();
|
|
194
|
+
await newPage.goto("https://another-site.com");
|
|
195
|
+
console.log("Other site title:", await newPage.title());
|
|
196
|
+
```
|
|
218
197
|
|
|
219
|
-
|
|
198
|
+
The session starts, runs your script, and exits.
|
|
220
199
|
|
|
221
|
-
|
|
222
|
-
- For each request, uses the **rules engine** to decide whether to route direct or via Aluvia.
|
|
223
|
-
- Because the proxy reads the latest config per-request, rule updates take effect immediately
|
|
200
|
+
### Option B: `connect()` (for AI agents and long-running processes)
|
|
224
201
|
|
|
225
|
-
|
|
202
|
+
Start a session as a background daemon, then connect from your application:
|
|
226
203
|
|
|
227
|
-
|
|
204
|
+
```bash
|
|
205
|
+
aluvia session start https://example.com --auto-unblock
|
|
206
|
+
```
|
|
228
207
|
|
|
229
|
-
|
|
208
|
+
```ts
|
|
209
|
+
import { connect } from "@aluvia/sdk";
|
|
230
210
|
|
|
231
|
-
|
|
211
|
+
// Auto-discovers the running session
|
|
212
|
+
const { page, browser, context, disconnect } = await connect();
|
|
213
|
+
console.log("URL:", page.url());
|
|
232
214
|
|
|
233
|
-
|
|
215
|
+
// When running multiple sessions, specify by name
|
|
216
|
+
const conn = await connect("swift-falcon");
|
|
217
|
+
console.log("URL:", conn.page.url());
|
|
234
218
|
|
|
235
|
-
|
|
219
|
+
// Disconnect when done (the session keeps running)
|
|
220
|
+
await disconnect();
|
|
221
|
+
```
|
|
236
222
|
|
|
237
|
-
|
|
238
|
-
- Credentials stay inside the SDK (nothing secret in your config)
|
|
239
|
-
- Rule changes apply immediately (no restarts)
|
|
223
|
+
Use this when your agent generates automation code dynamically at runtime or needs a persistent browser across multiple operations.
|
|
240
224
|
|
|
241
|
-
|
|
225
|
+
---
|
|
242
226
|
|
|
243
|
-
|
|
227
|
+
## Programmatic usage
|
|
244
228
|
|
|
245
|
-
|
|
229
|
+
For full control, use `AluviaClient` directly instead of the CLI.
|
|
246
230
|
|
|
247
|
-
|
|
231
|
+
### Basic example
|
|
248
232
|
|
|
249
|
-
|
|
233
|
+
```ts
|
|
234
|
+
import { AluviaClient } from "@aluvia/sdk";
|
|
235
|
+
import { chromium } from "playwright";
|
|
250
236
|
|
|
251
|
-
|
|
252
|
-
|
|
237
|
+
const client = new AluviaClient({
|
|
238
|
+
apiKey: process.env.ALUVIA_API_KEY!,
|
|
239
|
+
});
|
|
253
240
|
|
|
254
|
-
|
|
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");
|
|
255
245
|
|
|
256
|
-
|
|
246
|
+
// ... do your work ...
|
|
257
247
|
|
|
258
|
-
|
|
248
|
+
await browser.close();
|
|
249
|
+
await connection.close();
|
|
250
|
+
```
|
|
259
251
|
|
|
260
|
-
###
|
|
252
|
+
### With auto-launched browser
|
|
261
253
|
|
|
262
254
|
```ts
|
|
263
255
|
const client = new AluviaClient({
|
|
264
256
|
apiKey: process.env.ALUVIA_API_KEY!,
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
257
|
+
startPlaywright: true,
|
|
258
|
+
blockDetection: {
|
|
259
|
+
enabled: true,
|
|
260
|
+
autoUnblock: true,
|
|
261
|
+
},
|
|
268
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
|
|
269
269
|
```
|
|
270
270
|
|
|
271
|
-
|
|
271
|
+
### Runtime updates
|
|
272
272
|
|
|
273
|
-
|
|
273
|
+
While your agent is running, update routing, rotate IPs, or change geo — no restarts needed:
|
|
274
274
|
|
|
275
275
|
```ts
|
|
276
|
-
|
|
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
|
|
277
279
|
```
|
|
278
280
|
|
|
279
|
-
|
|
280
|
-
[Understanding the connection object](https://docs.aluvia.io/fundamentals/connections)
|
|
281
|
-
|
|
282
|
-
### 3. Use the connection with your tools
|
|
283
|
-
|
|
284
|
-
Pass the connection to your automation tool using the appropriate adapter:
|
|
281
|
+
### Constructor options
|
|
285
282
|
|
|
286
283
|
```ts
|
|
287
|
-
|
|
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
|
+
});
|
|
288
299
|
```
|
|
289
300
|
|
|
290
|
-
|
|
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.
|
|
308
|
+
|
|
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 |
|
|
291
324
|
|
|
292
|
-
|
|
325
|
+
### Examples
|
|
293
326
|
|
|
294
327
|
```ts
|
|
295
|
-
|
|
296
|
-
await client.
|
|
297
|
-
|
|
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([]);
|
|
298
339
|
```
|
|
299
340
|
|
|
300
|
-
|
|
341
|
+
Or from the CLI:
|
|
301
342
|
|
|
302
|
-
```
|
|
303
|
-
|
|
343
|
+
```bash
|
|
344
|
+
aluvia session set-rules "target-site.com,*.google.com"
|
|
345
|
+
aluvia session set-rules --remove "target-site.com"
|
|
304
346
|
```
|
|
305
347
|
|
|
306
348
|
---
|
|
307
349
|
|
|
308
|
-
##
|
|
350
|
+
## Block detection and auto-unblocking
|
|
309
351
|
|
|
310
|
-
|
|
352
|
+
Most proxy solutions require you to decide upfront which sites to proxy. If a site blocks you later, you're stuck.
|
|
311
353
|
|
|
312
|
-
|
|
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.
|
|
313
355
|
|
|
314
|
-
|
|
315
|
-
- through Aluvia's mobile proxy IPs,
|
|
356
|
+
### Automatic unblocking (recommended)
|
|
316
357
|
|
|
317
|
-
|
|
358
|
+
When a block is detected, the SDK adds the hostname to proxy rules and reloads the page through Aluvia:
|
|
318
359
|
|
|
319
|
-
|
|
320
|
-
|
|
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
|
+
```
|
|
375
|
+
|
|
376
|
+
Or from the CLI:
|
|
321
377
|
|
|
322
|
-
|
|
378
|
+
```bash
|
|
379
|
+
aluvia session start https://example.com --auto-unblock
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Detection-only mode
|
|
383
|
+
|
|
384
|
+
Run detection without automatic remediation. Your agent inspects the results and decides what to do:
|
|
323
385
|
|
|
324
386
|
```ts
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
+
}
|
|
329
395
|
```
|
|
330
396
|
|
|
331
|
-
###
|
|
397
|
+
### Block status scores
|
|
332
398
|
|
|
333
|
-
|
|
334
|
-
| --------------- | ------------------------------------- |
|
|
335
|
-
| `*` | All hostnames |
|
|
336
|
-
| `example.com` | Exact match |
|
|
337
|
-
| `*.example.com` | Subdomains of example.com |
|
|
338
|
-
| `google.*` | google.com, google.co.uk, and similar |
|
|
339
|
-
| `-example.com` | Exclude from proxying |
|
|
399
|
+
Each page analysis produces a score from 0.0 to 1.0:
|
|
340
400
|
|
|
341
|
-
|
|
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
|
|
342
410
|
|
|
343
|
-
|
|
411
|
+
Detection runs in two passes:
|
|
344
412
|
|
|
345
|
-
|
|
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.
|
|
346
415
|
|
|
347
|
-
|
|
416
|
+
The SDK also detects SPA navigations and tracks persistent blocks per hostname to prevent infinite retry loops.
|
|
348
417
|
|
|
349
|
-
|
|
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:
|
|
350
436
|
|
|
351
437
|
```ts
|
|
352
438
|
const response = await page.goto(url);
|
|
353
439
|
|
|
354
440
|
if (response?.status() === 403) {
|
|
355
|
-
// Blocked! Add this hostname to proxy rules and retry
|
|
356
441
|
await client.updateRules([...currentRules, new URL(url).hostname]);
|
|
357
|
-
await page.goto(url); //
|
|
442
|
+
await page.goto(url); // retried through Aluvia
|
|
358
443
|
}
|
|
359
444
|
```
|
|
360
445
|
|
|
361
|
-
|
|
446
|
+
For the full list of signal detectors and weights, see the [Client Technical Guide](docs/client-technical-guide.md#signal-detectors).
|
|
362
447
|
|
|
363
448
|
---
|
|
364
449
|
|
|
365
450
|
## Tool integration adapters
|
|
366
451
|
|
|
367
|
-
|
|
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
|
|
368
467
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
| Axios | `connection.asAxiosConfig()` | `{ proxy: false, httpAgent, httpsAgent }` |
|
|
376
|
-
| got | `connection.asGotOptions()` | `{ agent: { http, https } }` |
|
|
377
|
-
| fetch | `connection.asUndiciFetch()` | Proxy-enabled `fetch` function |
|
|
378
|
-
| Node.js http | `connection.asNodeAgents()` | `{ http: Agent, https: Agent }` |
|
|
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() });
|
|
379
474
|
|
|
380
|
-
|
|
475
|
+
// Axios
|
|
476
|
+
const axiosClient = axios.create(connection.asAxiosConfig());
|
|
477
|
+
await axiosClient.get("https://example.com");
|
|
478
|
+
|
|
479
|
+
// got
|
|
480
|
+
const gotClient = got.extend(connection.asGotOptions());
|
|
481
|
+
await gotClient("https://example.com");
|
|
482
|
+
|
|
483
|
+
// Node's fetch (via undici)
|
|
484
|
+
const myFetch = connection.asUndiciFetch();
|
|
485
|
+
await myFetch("https://example.com");
|
|
486
|
+
```
|
|
381
487
|
|
|
382
|
-
For more details
|
|
488
|
+
For more details, see the [Client Technical Guide](docs/client-technical-guide.md#tool-adapters).
|
|
383
489
|
|
|
384
490
|
---
|
|
385
491
|
|
|
386
|
-
##
|
|
387
|
-
|
|
388
|
-
`AluviaApi` is a typed wrapper for the Aluvia REST API. Use it to manage connections,
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|
403
|
-
│ │ │ │ │
|
|
404
|
-
│ ▼ ▼ ▼ │
|
|
405
|
-
│ ┌────────────────────────────────────────────────────┐ │
|
|
406
|
-
│ │ requestAndUnwrap / ctx.request │ │
|
|
407
|
-
│ │ (envelope unwrapping, error throwing) │ │
|
|
408
|
-
│ └────────────────────────────────────────────────────┘ │
|
|
409
|
-
│ │ │
|
|
410
|
-
│ ▼ │
|
|
411
|
-
│ ┌────────────────────────────────────────────────────┐ │
|
|
412
|
-
│ │ requestCore │ │
|
|
413
|
-
│ │ (URL building, headers, timeout, JSON parsing) │ │
|
|
414
|
-
│ └────────────────────────────────────────────────────┘ │
|
|
415
|
-
│ │ │
|
|
416
|
-
│ ▼ │
|
|
417
|
-
│ globalThis.fetch │
|
|
418
|
-
└───────────────────────────────────────────────────────────────┘
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
### What you can do
|
|
422
|
-
|
|
423
|
-
| Endpoint | Description |
|
|
424
|
-
| ------------------------------------ | --------------------------------------- |
|
|
425
|
-
| `api.account.get()` | Get account info (balance, usage) |
|
|
426
|
-
| `api.account.connections.list()` | List all connections |
|
|
427
|
-
| `api.account.connections.create()` | Create a new connection |
|
|
428
|
-
| `api.account.connections.get(id)` | Get connection details |
|
|
429
|
-
| `api.account.connections.patch(id)` | Update connection (rules, geo, session) |
|
|
430
|
-
| `api.account.connections.delete(id)` | Delete a connection |
|
|
431
|
-
| `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 |
|
|
432
508
|
|
|
433
509
|
### Example
|
|
434
510
|
|
|
@@ -442,12 +518,12 @@ const account = await api.account.get();
|
|
|
442
518
|
console.log("Balance:", account.balance_gb, "GB");
|
|
443
519
|
|
|
444
520
|
// Create a connection for a new agent
|
|
445
|
-
const
|
|
521
|
+
const conn = await api.account.connections.create({
|
|
446
522
|
description: "pricing-scraper",
|
|
447
523
|
rules: ["competitor-site.com"],
|
|
448
524
|
target_geo: "us_ca",
|
|
449
525
|
});
|
|
450
|
-
console.log("Created:",
|
|
526
|
+
console.log("Created connection:", conn.connection_id);
|
|
451
527
|
|
|
452
528
|
// List available geos
|
|
453
529
|
const geos = await api.geos.list();
|
|
@@ -457,12 +533,60 @@ console.log(
|
|
|
457
533
|
);
|
|
458
534
|
```
|
|
459
535
|
|
|
460
|
-
|
|
536
|
+
`AluviaApi` is also available as `client.api` when using `AluviaClient`.
|
|
461
537
|
|
|
462
|
-
For the complete API reference, see [API Technical Guide](docs/api-technical-guide.md).
|
|
538
|
+
For the complete API reference, see the [API Technical Guide](docs/api-technical-guide.md).
|
|
463
539
|
|
|
464
540
|
---
|
|
465
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
|
+
└─────────────────────────────┴───────────────────────────────────┘
|
|
558
|
+
```
|
|
559
|
+
|
|
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).
|
|
561
|
+
|
|
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
|
+
```
|
|
577
|
+
|
|
578
|
+
---
|
|
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
|
+
|
|
466
590
|
## License
|
|
467
591
|
|
|
468
592
|
MIT — see [LICENSE](./LICENSE)
|