Node.js native bindings for libcurl-impersonate. Impersonate Chrome, Edge, Firefox and Safari TLS fingerprints.
npm install node-libcurl-ja3[![NPM version][npm-image]][npm-url]
[![license][license-image]][license-url]
[npm-image]:https://img.shields.io/npm/v/node-libcurl-ja3.svg?style=flat-square
[npm-url]:https://www.npmjs.org/package/node-libcurl-ja3
[license-image]:https://img.shields.io/npm/l/node-libcurl-ja3?style=flat-square
[license-url]:https://raw.githubusercontent.com/andrewmackrodt/node-libcurl-ja3/develop/LICENSE
This is a fork of node-libcurl using patches from lexiforest/curl-impersonate
to impersonate the four major browsers: Chrome, Edge, Safari and Firefox. node-libcurl-ja3 is able to
perform TLS and HTTP handshakes that are identical to that of a real browser.
Only the following platforms are supported:
- Linux 64-bit (glibc based)
- macOS Apple Silicon (M1+)
Prebuilt binaries are provided for Node.js 20, 22 and 24. Any other version has not been tested and will need an
environment capable of building the native module. Refer to Important Notes on Prebuilt Binaries / Direct Installation
for a list of required system packages.
Although the library is named node-libcurl-ja3, it also supports http2 and ja4 impersonation (e.g. Akamai).
- Quick Start
- Install
- Impersonate Usage
- Simple Impersonate Request - Async / Await using curly
- Simple Impersonate Request - Using Curl class
- Simple Request - Async / Await using curly
- Simple Request - Using Curl class
- Setting HTTP headers
- Form Submission (Content-Type: application/x-www-form-urlencoded)
- MultiPart Upload / HttpPost libcurl Option (Content-Type: multipart/form-data)
- Binary Data
- API
- Special Notes
- READFUNCTION option
- Common Issues
- Benchmarks
- Detailed Installation
- Important Notes on Prebuilt Binaries / Direct Installation
- Missing Packages
- Building on Linux
- Building on macOS
- Contributing
- Acknowledgments
- This library cannot be used in a browser, it depends on native code.
- There is no worker threads support at the moment. See #169
shell
npm i node-libcurl-ja3 --save
`
or
`shell
yarn add node-libcurl-ja3
`$3
The following browser fingerprints are pre-configured:
- Chrome 143
- Edge 143
- Firefox 144.0
- Safari 18.6
To learn how to configure custom impersonation options, refer to the folder lib/impersonate/browser.
For brevity, this section covers a single example for creating impersonate instances using the curly API and Curl class.
To use impersonation with the examples following this section, adapt them to use either:
-
impersonate in place of curly
- Curl.impersonate in place of new Curl#### Simple Impersonate Request - Async / Await using curly
`javascript
const { Browser, impersonate } = require('node-libcurl-ja3');const curly = impersonate(Browser.Chrome);
const { data } = await curly.get('https://tls.browserleaks.com/json');
console.log(data.ja3n_hash); // 8e19337e7524d2573be54efb2b0784c9
`#### Simple Impersonate Request - Using Curl class
`javascript
const { Browser, Curl } = require('node-libcurl-ja3');const curl = Curl.impersonate(Browser.Chrome);
curl.setOpt('URL', 'tls.browserleaks.com/json');
curl.setOpt('FOLLOWLOCATION', true);
curl.on('end', function (statusCode, data, headers) {
console.info(statusCode);
console.info('---');
console.info(data.length);
console.info('---');
console.info(this.getInfo('TOTAL_TIME'));
this.close();
});
curl.on('error', curl.close.bind(curl));
curl.perform();
`$3
this API is experimental and is subject to changes without a major version bump
`javascript
const { curly } = require('node-libcurl-ja3');const { statusCode, data, headers } = await curly.get('http://www.google.com')
`Any option can be passed using their
FULLNAME or a lowerPascalCase format:
`javascript
const querystring = require('querystring');
const { curly } = require('node-libcurl-ja3');const { statusCode, data, headers } = await curly.post('http://httpbin.com/post', {
postFields: querystring.stringify({
field: 'value',
}),
// can use
postFields or POSTFIELDS
})
`JSON POST example:
`javascript
const { curly } = require('node-libcurl-ja3')
const { data } = await curly.post('http://httpbin.com/post', {
postFields: JSON.stringify({ field: 'value' }),
httpHeader: [
'Content-Type: application/json',
'Accept: application/json'
],
})console.log(data)
`$3
`javascript
const { Curl } = require('node-libcurl-ja3');const curl = new Curl();
curl.setOpt('URL', 'www.google.com');
curl.setOpt('FOLLOWLOCATION', true);
curl.on('end', function (statusCode, data, headers) {
console.info(statusCode);
console.info('---');
console.info(data.length);
console.info('---');
console.info(this.getInfo( 'TOTAL_TIME'));
this.close();
});
curl.on('error', curl.close.bind(curl));
curl.perform();
`$3
Pass an array of strings specifying headers
`javascript
curl.setOpt(Curl.option.HTTPHEADER,
['Content-Type: application/x-amz-json-1.1'])
`$3
`javascript
const querystring = require('querystring');
const { Curl } = require('node-libcurl-ja3');const curl = new Curl();
const close = curl.close.bind(curl);
curl.setOpt(Curl.option.URL, '127.0.0.1/upload');
curl.setOpt(Curl.option.POST, true)
curl.setOpt(Curl.option.POSTFIELDS, querystring.stringify({
field: 'value',
}));
curl.on('end', close);
curl.on('error', close);
`$3
`javascript
const { Curl } = require('node-libcurl-ja3');const curl = new Curl();
const close = curl.close.bind(curl);
curl.setOpt(Curl.option.URL, '127.0.0.1/upload.php');
curl.setOpt(Curl.option.HTTPPOST, [
{ name: 'input-name', file: '/file/path', type: 'text/html' },
{ name: 'input-name2', contents: 'field-contents' }
]);
curl.on('end', close);
curl.on('error', close);
`$3
When requesting binary data make sure to do one of these:
- Pass your own
WRITEFUNCTION (https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html):
`javascript
curl.setOpt('WRITEFUNCTION', (buffer, size, nmemb) => {
// something
})
`
- Enable one of the following flags:
`javascript
curl.enable(CurlFeature.NoDataParsing)
// or
curl.enable(CurlFeature.Raw)
`The reasoning behind this is that by default, the
Curl instance will try to decode the received data and headers to utf8 strings, as can be seen here: https://github.com/JCMais/node-libcurl/blob/b55b13529c9d11fdcdd7959137d8030b39427800/lib/Curl.ts#L391For more examples check the examples folder.
API
This library provides Typescript type definitions.
Almost all CURL options are supported, if you pass one that is not, an error will be thrown.
For more usage examples check the examples folder.
Special Notes
$3
The buffer passed as first parameter to the callback set with the
READFUNCTION option is initialized with the size libcurl is using in their upload buffer (which can be set with UPLOAD_BUFFERSIZE), this is initialized using node::Buffer::Data(buf); which is basically the same than Buffer#allocUnsafe and therefore, it has all the implications as to its correct usage: https://nodejs.org/pt-br/docs/guides/buffer-constructor-deprecation/#regarding-buffer-allocunsafeSo, be careful, make sure to return exactly the amount of data you have written to the buffer on this callback. Only that specific amount is going to be copied and handed over to libcurl.
Common Issues
See COMMON_ISSUES.md
Benchmarks
See ./benchmark
Detailed Installation
The latest version of this package has prebuilt binaries (thanks to node-pre-gyp)
available for:
- Node.js: Latest two versions on active LTS (see https://github.com/nodejs/Release)
And on the following platforms:
- Linux 64-bit (glibc based)
- macOS Apple Silicon (M1+)
Installing with
yarn add node-libcurl-ja3 or npm install node-libcurl-ja3 should download a prebuilt binary and no compilation will be needed.The prebuilt binary is statically built with the following library versions, features and protocols:
`
Versions: libcurl/8.15.0-IMPERSONATE BoringSSL zlib/1.3.1 brotli/1.1.0 zstd/1.5.7 c-ares/1.34.5 nghttp2/1.63.0 ngtcp2/1.11.0 nghttp3/1.9.0
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli ECH HSTS HTTP2 HTTP3 HTTPS-proxy HTTPSRR IPv6 Largefile libz NTLM SSL SSLS-EXPORT threadsafe UnixSockets zstd
`If there is no prebuilt binary available that matches your system, or if the installation fails, then you will need an environment capable of compiling Node.js addons, which means:
- python 3.x installed
- updated C++ compiler able to compile C++17.
If you don't want to use the prebuilt binary even if it works on your system, you can pass a flag when installing:
With npm:
`sh
npm install node-libcurl-ja3 --build-from-source
`With yarn:
`sh
npm_config_build_from_source=true yarn add node-libcurl-ja3
`$3
The built binaries are statically linked with
BoringSSL, brotli, nghttp2, zlib and zstd. #### Missing Packages
The built binaries do not have support for
GSASL, GSS-API, HTTP3, IDN, LDAP, LDAPS, PSL, RTMP, SPNEGO, SSH, SSPI or TLS-SRP.$3
If you are on a debian based system, install the required dependencies by running:
`bash
sudo apt install -qqy autoconf automake build-essential cmake curl libtool ninja-build pkg-config
`Users for other distributions will need to find the equivalent packages and install via your package manager.
$3
On macOS you must have:
- macOS >= 11.6 (Big Sur)
- Xcode Command Line Tools
- Homebrew
- Bash >= 5.0 (unconfirmed)
You can check if you have Xcode Command Line Tools be running:
`sh
xcode-select -p
`
It should return their path, in case it returns nothing, you must install it by running:
`sh
xcode-select --install
`Finally, install the remaining packages using homebrew:
`sh
brew install automake bash cmake libtool make meson ninja
``Read CONTRIBUTING.md
[a1]: https://github.com/JCMais/node-libcurl
[a2]: https://github.com/lexiforest/curl-impersonate
[a3]: https://github.com/galihrivanto/node-libcurli
[a4]: https://github.com/Ossianaa/node-libcurl