A powerful Node.js wrapper for curl-impersonate
Make HTTP requests that mimic real browser behavior and bypass anti-bot protections with ease.
Features • Installation • Quick Start • Documentation • Examples
tar for binary extractionnpm install cuimp
import { get, post, createCuimpHttp } from 'cuimp'
// Simple GET request
const response = await get('https://httpbin.org/headers')
console.log(response.data)
// POST with data
const result = await post('https://httpbin.org/post', {
name: 'John Doe',
email: 'john@example.com',
})
// Using HTTP client instance
const client = createCuimpHttp({
descriptor: { browser: 'chrome', version: '123' },
})
const data = await client.get('https://api.example.com/users')
import { get, createCuimpHttp } from 'cuimp'
// Create a client that mimics Chrome 123
const scraper = createCuimpHttp({
descriptor: { browser: 'chrome', version: '123' },
})
// Scrape a website that blocks regular requests
const response = await scraper.get('https://example.com/protected-content', {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
},
})
console.log('Scraped content:', response.data)
import { createCuimpHttp } from 'cuimp'
// Test your API with different browser signatures
const browsers = ['chrome', 'firefox', 'safari', 'edge']
for (const browser of browsers) {
const client = createCuimpHttp({
descriptor: { browser, version: 'latest' },
})
const response = await client.get('https://your-api.com/test')
console.log(`${browser}: ${response.status}`)
}
import { createCuimpHttp } from 'cuimp'
// Enable automatic cookie management
const client = createCuimpHttp({
descriptor: { browser: 'chrome', version: '123' },
cookieJar: true, // Cookies are automatically stored and sent
})
// First request - server sets cookies
await client.get('https://httpbin.org/cookies/set/session_id/abc123')
// Second request - cookies are automatically included
const response = await client.get('https://httpbin.org/cookies')
console.log(response.data.cookies) // { session_id: 'abc123' }
// Access cookies programmatically
const cookieJar = client.getCookieJar()
const cookies = cookieJar.getCookies()
// Clear cookies
client.clearCookies()
// Clean up when done (removes temp cookie file)
client.destroy()
import { request } from 'cuimp'
// HTTP proxy
const response1 = await request({
url: 'https://httpbin.org/ip',
proxy: 'http://proxy.example.com:8080',
})
// SOCKS5 proxy with authentication
const response2 = await request({
url: 'https://httpbin.org/ip',
proxy: 'socks5://user:pass@proxy.example.com:1080',
})
// Automatic proxy detection from environment variables
// HTTP_PROXY, HTTPS_PROXY, ALL_PROXY
const response3 = await request({
url: 'https://httpbin.org/ip',
// Will automatically use HTTP_PROXY if set
})
import { requestStream } from 'cuimp'
await requestStream(
{ url: 'https://httpbin.org/stream/3', extraCurlArgs: ['--no-buffer'] },
{
onHeaders: ({ status, headers }) => {
console.log('status', status)
console.log('content-type', headers['Content-Type'])
},
onData: chunk => {
process.stdout.write(chunk)
},
onEnd: info => {
console.log('done', info.status)
},
onError: err => {
console.error('stream error', err)
},
}
)
Note: For streaming (SSE or chunked responses), include --no-buffer in extraCurlArgs so curl flushes output immediately. You can also set it on the client defaults:
const client = createCuimpHttp({ extraCurlArgs: ['--no-buffer'] })
await client.requestStream({ url: 'https://httpbin.org/stream/3' }, { onData: chunk => {} })
If you want the full body, enable buffering:
const res = await requestStream({ url: 'https://httpbin.org/stream/3' }, { collectBody: true })
console.log(res.rawBody?.toString('utf8'))
import { Cuimp, downloadBinary } from 'cuimp'
// Method 1: Using Cuimp class
const cuimp = new Cuimp({ descriptor: { browser: 'chrome' } })
const binaryInfo = await cuimp.download()
console.log('Downloaded:', binaryInfo.binaryPath)
// Method 2: Using convenience function
const info = await downloadBinary({
descriptor: { browser: 'firefox', version: '133' },
})
// Pre-download multiple browsers for offline use
const browsers = ['chrome', 'firefox', 'safari', 'edge']
for (const browser of browsers) {
await downloadBinary({ descriptor: { browser } })
console.log(`${browser} binary ready`)
}
import { createCuimpHttp } from 'cuimp'
// Suppress all logs
const silentLogger = {
info: () => {},
warn: () => {},
error: () => {},
debug: () => {},
}
const client = createCuimpHttp({
descriptor: { browser: 'chrome' },
logger: silentLogger,
})
// Or use a structured logger (Winston, Pino, etc.)
const client = createCuimpHttp({
descriptor: { browser: 'chrome' },
logger: myStructuredLogger,
})
get(url, config?)Make a GET request.
const response = await get('https://api.example.com/users')
post(url, data?, config?)Make a POST request.
const response = await post('https://api.example.com/users', {
name: 'John Doe',
email: 'john@example.com',
})
put(url, data?, config?)Make a PUT request.
patch(url, data?, config?)Make a PATCH request.
del(url, config?)Make a DELETE request.
head(url, config?)Make a HEAD request.
options(url, config?)Make an OPTIONS request.
downloadBinary(options?)Download curl-impersonate binary without making HTTP requests.
// Download default binary
const info = await downloadBinary()
// Download specific browser binary
const chromeInfo = await downloadBinary({
descriptor: { browser: 'chrome', version: '123' },
})
createCuimpHttp(options?)Create an HTTP client instance.
const client = createCuimpHttp({
descriptor: { browser: 'chrome', version: '123' },
path: '/custom/path/to/binary',
})
// Use the client
const response = await client.get('https://api.example.com/data')
request(config)Make a request with full configuration.
const response = await request({
url: 'https://api.example.com/users',
method: 'POST',
headers: {
Authorization: 'Bearer token',
'Content-Type': 'application/json',
},
data: { name: 'John Doe' },
timeout: 5000,
})
requestStream(config, handlers?)Stream a response body incrementally with callbacks.
const res = await requestStream(
{ url: 'https://httpbin.org/stream/3' },
{
onHeaders: ({ status }) => console.log('status', status),
onData: chunk => process.stdout.write(chunk),
onEnd: info => console.log('done', info.status),
onError: err => console.error(err),
}
)
handlers supports:
interface CuimpStreamHandlers {
onHeaders?: (info: {
status: number
statusText: string
headers: Record<string, string>
}) => void
onData?: (chunk: Buffer) => void
onEnd?: (info: CuimpStreamResponse) => void
onError?: (error: Error) => void
collectBody?: boolean
}
CuimpThe core class for managing curl-impersonate binaries and descriptors.
import { Cuimp } from 'cuimp'
const cuimp = new Cuimp({
descriptor: { browser: 'chrome', version: '123' },
path: '/custom/path',
})
// Verify binary
const info = await cuimp.verifyBinary()
// Build command preview
const command = cuimp.buildCommandPreview('https://example.com', 'GET')
// Download binary without verification
const binaryInfo = await cuimp.download()
CuimpHttpHTTP client class that wraps the Cuimp core.
import { CuimpHttp, Cuimp } from 'cuimp'
const core = new Cuimp()
const client = new CuimpHttp(core, {
baseURL: 'https://api.example.com',
timeout: 10000,
})
CuimpHttp also supports streaming via client.requestStream(config, handlers).
Configure which browser to impersonate:
interface CuimpDescriptor {
browser?: 'chrome' | 'firefox' | 'edge' | 'safari'
version?: string // e.g., '136', '2601', '133a', or 'latest' (default)
architecture?: 'x64' | 'arm64' | 'arm'
platform?: 'linux' | 'windows' | 'macos' | 'ios' | 'android'
forceDownload?: boolean // Force re-download even if binary exists
}
Platform values are lowercase (ios, macos); aliases like iOS or macOS are normalized automatically.
When you set platform: 'ios' or platform: 'android' on a desktop host, cuimp downloads the host OS binary (e.g. macOS on a Mac) and selects the browser fingerprint via browser + version (e.g. curl_safari2601). Native iOS/Android binaries are used when running on that OS, or set path to a preinstalled binary.
Request configuration options:
interface CuimpRequestConfig {
url: string
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'
headers?: Record<string, string>
data?: any
timeout?: number
maxRedirects?: number
proxy?: string // HTTP, HTTPS, or SOCKS proxy URL
insecureTLS?: boolean // Skip TLS certificate verification
signal?: AbortSignal // Request cancellation
}
Core options:
interface CuimpOptions {
descriptor?: CuimpDescriptor
path?: string // Custom path to curl-impersonate binary
extraCurlArgs?: string[] // Global curl arguments applied to all requests
logger?: Logger // Custom logger for binary download/verification messages
proxy?: string // Default proxy for all requests (HTTP, HTTPS, or SOCKS URL)
cookieJar?: boolean | string // Enable automatic cookie management
autoDownload?: boolean // If false, throw error instead of auto-downloading binaries (default: true)
}
Set a default proxy for all requests when creating the client. Per-request proxy in CuimpRequestConfig overrides this.
// Session-level proxy: all requests use this proxy by default
const client = createCuimpHttp({
proxy: 'http://proxy.example.com:8080',
})
await client.get('https://api.example.com/data') // Uses the proxy
// Override for a single request
await client.get('https://api.example.com/other', {
proxy: 'socks5://other-proxy:1080',
})
Supported proxy URL formats: http://host:port, https://host:port, socks4://host:port, socks5://host:port, or host:port (defaults to HTTP). Authentication: http://user:pass@host:port.
The cookieJar option enables automatic cookie management:
```typescript // Option 1: Automatic temp file (cleaned up on destroy) const client = createCuimpHttp({ cookieJar: true, })
// Option 2: Custom file path (persists between runs) // Recommended: Use user home directory for security import os from 'os' import path from 'path'
const cookiePath = path.join(os.homedir(), '.
$ claude mcp add cuimp-ts \
-- python -m otcore.mcp_server <graph>