clonbrowser-client
v0.2.0
Published
Unofficial fully typed client for ClonBrowser authentication, proxies, and profiles.
Maintainers
Readme
clonbrowser-client
An unofficial, fully typed TypeScript client for ClonBrowser dashboard authentication, proxy management, and profile management.
[!IMPORTANT] This package wraps the private dashboard gateway observed in ClonBrowser 6.3.6. It is not ClonBrowser's local OpenAPI, is not affiliated with ClonBrowser, and may require updates when the desktop application changes.
Requirements
- Node.js 20 or newer
- A ClonBrowser account authorized to manage the relevant proxies and profiles
Installation
npm install clonbrowser-clientLogin
import { ClonBrowserClient } from "clonbrowser-client";
const client = await ClonBrowserClient.login({
authId: process.env.CLONBROWSER_AUTH_ID!,
password: process.env.CLONBROWSER_PASSWORD!,
});The client generates a device UUID and reuses it for authenticated requests. Persist both token and deviceId if you need to recreate the session later:
const session = {
token: client.token,
deviceId: client.deviceId,
clientVersion: client.clientVersion,
};
const restoredClient = new ClonBrowserClient(session);
// Uses the same HEAD request observed when the desktop app restores a session.
await restoredClient.validateToken();You can provide a stable device UUID during login:
const client = await ClonBrowserClient.login(
{ authId, password },
{ deviceId: "00000000-0000-4000-8000-000000000000" },
);If ClonBrowser requires phone binding, a PIN, or two-factor authentication, login throws ClonBrowserAuthenticationChallengeError with typed challenge fields. This initial client reports the challenge but does not complete the secondary flow.
Proxy management
List proxies
const page = await client.proxies.list({
page: 1,
size: 50,
groupId: "group-id",
});
for (const proxy of page.items) {
console.log(proxy.proxyId, proxy.address, proxy.port);
}The optional search list setting is ClonBrowser's raw dashboard sort/filter expression, not a plain-text search term. Omit it to use the captured dashboard ordering.
Get a proxy
const proxy = await client.proxies.get("proxy-id");Create a proxy
const { guid } = await client.proxies.create({
address: "proxy.example.com",
port: 8443,
proxyType: "https",
username: "proxy-user",
password: "proxy-password",
alias: "Primary proxy",
remark: "Managed by our application",
groupIds: [],
tagIds: [],
});expiredTime, when provided, is the Unix timestamp in seconds used by the ClonBrowser dashboard.
Update a proxy
The dashboard update endpoint expects a complete proxy definition:
const updated = await client.proxies.update("proxy-id", {
address: "new-proxy.example.com",
port: 9443,
proxyType: "https",
username: "new-user",
password: "new-password",
alias: "Updated proxy",
remark: "Updated by our application",
});Delete a proxy
await client.proxies.delete("proxy-id");
// Delete even when ClonBrowser considers the proxy to be in use.
await client.proxies.delete("proxy-id", { force: true });Profile management
List and get profiles
const page = await client.profiles.list({
page: 1,
size: 50,
groupId: "group-id",
});
const profile = await client.profiles.get(page.items[0]!.guid);As with proxy lists, omit search to use the dashboard's captured sort expression.
Create a profile
The client asks ClonBrowser's cloud gateway to generate a matching fingerprint template before creating the profile:
const { guid: profileId } = await client.profiles.create({
name: "Managed profile",
systemOS: "windows",
systemVersions: ["11"],
kernelBrand: "chrome",
kernelVersion: 149,
region: "andorra_la_vella",
proxyId: "proxy-id",
remark: "Managed by our application",
defaultUrls: ["https://example.com"],
settings: {
cookieSync: true,
enableBrowserWorkbenchPage: true,
},
});Profile settings, fingerprint overrides, accounts, proxy binding, URLs, tags, and returned profile data are fully typed. ClonBrowser can add supported operating systems, regions, kernels, and enum values over time, so the corresponding string types remain forward-compatible.
Edit a profile
Updates are partial at the SDK boundary. The client first retrieves the current profile and then sends the complete PUT payload required by the dashboard, preserving settings you did not change:
await client.profiles.update(profileId, {
name: "Renamed profile",
remark: "Updated by our application",
proxyId: "another-proxy-id",
settings: {
cookieSync: false,
},
});
// Set proxyId to null to remove the profile's proxy binding.
await client.profiles.update(profileId, { proxyId: null });Update profile cookies
ClonBrowser's cloud profile update accepts its cookie-import payload as a string:
const cookieImport = JSON.stringify([
{
domain: ".example.com",
name: "session",
value: process.env.EXAMPLE_SESSION_COOKIE!,
},
]);
await client.profiles.updateCookies(profileId, cookieImport);The cloud profile-detail response does not return cookie data, so the SDK intentionally does not expose getCookies().
Delete a profile
await client.profiles.delete(profileId);Existing tokens and configuration
const client = new ClonBrowserClient({
token,
deviceId,
clientVersion: "6.3.6",
language: "en-US",
baseUrl: "https://gateway.clonbrowser.com/cb/app",
});clientVersion, language, and baseUrl have defaults and normally do not need to be supplied. The fetch option accepts a fully typed Fetch-compatible implementation for testing or controlled runtimes.
Errors
Non-successful HTTP responses throw ClonBrowserApiError:
import { ClonBrowserApiError } from "clonbrowser-client";
try {
await client.proxies.get("missing-proxy");
} catch (error) {
if (error instanceof ClonBrowserApiError) {
console.error(error.status, error.method, error.responseBody);
}
}Request bodies and credentials are deliberately not attached to errors.
Security
Tokens, account passwords, proxy credentials, profile account credentials, and cookies are secrets. Do not log them or commit them to source control. This client does not persist credentials, tokens, or cookies.
End-to-end testing
The live test exercises login, token validation, and every proxy and profile operation against a dedicated ClonBrowser test account:
CLONBROWSER_E2E_EMAIL="[email protected]" \
CLONBROWSER_E2E_PASSWORD="test-password" \
npm run test:e2eThe GitHub Actions E2E job runs after compatibility and package-quality checks on every push to main. Configure these repository secrets:
CLONBROWSER_E2E_EMAILCLONBROWSER_E2E_PASSWORD
The test treats all pre-existing account data as read-only. It mutates only IDs returned by its own create calls, records those IDs in a per-run ownership set, and verifies a unique ownership marker before every update or deletion. A finally cleanup deletes owned profiles before owned proxies, including when an assertion or request fails. Runs are serialized so two CI jobs cannot operate on the test account concurrently.
Automated releases
After the complete CI workflow succeeds for a push to main, semantic-release determines the next version from Conventional Commits, publishes the package to npm, creates the GitHub release, and tags the tested revision. Documentation and CI-only commits do not publish a new package unless another releasable commit is present.
Publishing uses npm trusted publishing rather than a long-lived npm token. Configure the clonbrowser-client package's trusted publisher on npm with:
- Provider: GitHub Actions
- Organization:
SimCall - Repository:
clonbrowser-client - Workflow filename:
release.yml - Allowed action:
npm publish
The release workflow uses Node.js 24.10 and npm 11.8, satisfying npm's OIDC requirements. No NPM_TOKEN repository secret is needed.
License
MIT
