Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Curlimpersonate
https://github.com/tcortega/curlimpersonate
Admin
A curl wrapper that can impersonate a browser, allowing users to mimic real browser requests.
Tokens:
8,293
Snippets:
25
Trust Score:
7.8
Update:
1 month ago
Context
Skills
Chat
Benchmark
33.5
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# CurlImpersonate.Net CurlImpersonate.Net is a .NET wrapper library for curl-impersonate, enabling HTTP requests that impersonate real browser TLS fingerprints. It provides low-level P/Invoke bindings to the curl-impersonate native library, allowing .NET applications to make web requests that appear to come from Chrome, Firefox, Safari, Edge, or Tor browsers. The library supports browser profiles ranging from Chrome 99 to Chrome 142, Firefox 133-144, Safari 15.3 to 26.0.1, Edge 99-101, and Tor 145. The library is designed for scenarios where anti-bot detection systems fingerprint TLS connections (JA3, JA4, Akamai fingerprints) to identify and block non-browser clients. By using curl-impersonate's modified TLS/SSL stack, requests generate authentic browser fingerprints that match real browsers. The library targets .NET 10.0 with AOT compatibility and provides both synchronous (easy) and asynchronous (multi) curl interfaces. ## CurlGlobal.Initialize Initializes the curl library globally. This is called automatically via module initializer on first use, but can be called explicitly for custom initialization flags. ```csharp using CurlImpersonate; // Automatic initialization happens on first EasyInit call // Or initialize explicitly with custom flags CurlGlobal.Initialize(NativeMethods.CURL_GLOBAL_ALL); // Check initialization status if (CurlGlobal.IsInitialized) { Console.WriteLine($"Curl version: {CurlGlobal.Version}"); // Output: Curl version: libcurl/8.11.1-DEV BoringSSL zlib/1.3.1 brotli/1.1.0 zstd/1.5.6 nghttp2/1.64.0 } // Cleanup (usually not needed - happens at process exit) CurlGlobal.Cleanup(); ``` ## NativeMethods.EasyInit Creates a new curl easy handle for performing HTTP transfers. Returns a native pointer that must be cleaned up with EasyCleanup. ```csharp using System.Runtime.InteropServices; using CurlImpersonate.Enums; using CurlImpersonate.Native; // Create a curl easy handle nint curl = NativeMethods.EasyInit(); if (curl == 0) throw new Exception("Failed to initialize curl handle"); try { // Use the handle for HTTP operations var urlPtr = Marshal.StringToHGlobalAnsi("https://httpbin.org/get"); var result = NativeMethods.EasySetOpt(curl, CurlOption.Url, urlPtr); Marshal.FreeHGlobal(urlPtr); if (result != CurlCode.Ok) throw new CurlException(result, "Failed to set URL"); } finally { // Always cleanup the handle NativeMethods.EasyCleanup(curl); } ``` ## NativeMethods.EasyImpersonate Configures browser impersonation on a curl easy handle. Sets TLS fingerprint, cipher suites, and HTTP/2 settings to match a specific browser profile. ```csharp using System.Runtime.InteropServices; using CurlImpersonate.Enums; using CurlImpersonate.Native; nint curl = NativeMethods.EasyInit(); try { // Impersonate Chrome 142 with default headers var result = NativeMethods.EasyImpersonate( curl, BrowserProfile.Chrome142.ToTargetString(), // "chrome142" defaultHeaders: 1 // 1 = include default browser headers ); if (result != CurlCode.Ok) throw new CurlException(result, "Failed to set browser impersonation"); // Alternative browser profiles NativeMethods.EasyImpersonate(curl, "firefox144", 1); // Firefox 144 NativeMethods.EasyImpersonate(curl, "safari2601", 1); // Safari 26.0.1 NativeMethods.EasyImpersonate(curl, "edge101", 1); // Edge 101 NativeMethods.EasyImpersonate(curl, "tor145", 1); // Tor Browser 145 NativeMethods.EasyImpersonate(curl, "chrome131_android", 1); // Chrome 131 Android } finally { NativeMethods.EasyCleanup(curl); } ``` ## NativeMethods.EasySetOpt Sets options on a curl easy handle using the variadic wrapper shim. Supports URL, headers, callbacks, timeouts, SSL options, and curl-impersonate specific options. ```csharp using System.Runtime.InteropServices; using CurlImpersonate.Enums; using CurlImpersonate.Native; nint curl = NativeMethods.EasyInit(); var urlPtr = Marshal.StringToHGlobalAnsi("https://httpbin.org/post"); var postData = Marshal.StringToHGlobalAnsi("{\"key\": \"value\"}"); var contentType = Marshal.StringToHGlobalAnsi("Content-Type: application/json"); try { // Set URL NativeMethods.EasySetOpt(curl, CurlOption.Url, urlPtr); // Enable POST NativeMethods.EasySetOpt(curl, CurlOption.Post, (nint)1); NativeMethods.EasySetOpt(curl, CurlOption.PostFields, postData); // Set custom headers using slist nint headers = NativeMethods.SlistAppend(0, "Content-Type: application/json"); headers = NativeMethods.SlistAppend(headers, "X-Custom-Header: value"); NativeMethods.EasySetOpt(curl, CurlOption.HttpHeader, headers); // Set timeouts NativeMethods.EasySetOpt(curl, CurlOption.TimeoutMs, (nint)30000); // 30s total NativeMethods.EasySetOpt(curl, CurlOption.ConnectTimeoutMs, (nint)10000); // 10s connect // Follow redirects NativeMethods.EasySetOpt(curl, CurlOption.FollowLocation, (nint)1); NativeMethods.EasySetOpt(curl, CurlOption.MaxRedirs, (nint)10); // Enable automatic decompression var encoding = Marshal.StringToHGlobalAnsi(""); NativeMethods.EasySetOpt(curl, CurlOption.AcceptEncoding, encoding); Marshal.FreeHGlobal(encoding); // SSL verification NativeMethods.EasySetOpt(curl, CurlOption.SslVerifyPeer, (nint)1); NativeMethods.EasySetOpt(curl, CurlOption.SslVerifyHost, (nint)2); // Free headers when done NativeMethods.SlistFreeAll(headers); } finally { Marshal.FreeHGlobal(urlPtr); Marshal.FreeHGlobal(postData); NativeMethods.EasyCleanup(curl); } ``` ## NativeMethods.EasyPerform Performs a blocking HTTP transfer using the configured curl easy handle. Returns CurlCode indicating success or failure. ```csharp using System.Runtime.InteropServices; using System.Text; using CurlImpersonate.Enums; using CurlImpersonate.Native; nint curl = NativeMethods.EasyInit(); var urlPtr = Marshal.StringToHGlobalAnsi("https://httpbin.org/get"); var responseData = new StringBuilder(); unsafe { // Define write callback to capture response WriteCallback writeCallback = (ptr, size, nmemb, userdata) => { var totalSize = size * nmemb; var data = new byte[totalSize]; Marshal.Copy((nint)ptr, data, 0, (int)totalSize); responseData.Append(Encoding.UTF8.GetString(data)); return totalSize; }; var callbackPtr = Marshal.GetFunctionPointerForDelegate(writeCallback); try { NativeMethods.EasySetOpt(curl, CurlOption.Url, urlPtr); NativeMethods.EasySetOpt(curl, CurlOption.WriteFunction, callbackPtr); // Enable auto decompression var encoding = Marshal.StringToHGlobalAnsi(""); NativeMethods.EasySetOpt(curl, CurlOption.AcceptEncoding, encoding); Marshal.FreeHGlobal(encoding); // Impersonate Chrome NativeMethods.EasyImpersonate(curl, "chrome142", 1); // Perform the request var result = NativeMethods.EasyPerform(curl); if (result != CurlCode.Ok) { var errorMsg = CurlException.GetErrorMessage(result); throw new CurlException(result, $"Request failed: {errorMsg}"); } // Keep callback alive until perform completes GC.KeepAlive(writeCallback); Console.WriteLine($"Response: {responseData}"); } finally { Marshal.FreeHGlobal(urlPtr); NativeMethods.EasyCleanup(curl); } } ``` ## NativeMethods.EasyGetInfo Retrieves information about a completed transfer such as response code, timing, and effective URL. ```csharp using System.Runtime.InteropServices; using CurlImpersonate.Enums; using CurlImpersonate.Native; nint curl = NativeMethods.EasyInit(); var urlPtr = Marshal.StringToHGlobalAnsi("https://httpbin.org/status/200"); try { NativeMethods.EasySetOpt(curl, CurlOption.Url, urlPtr); NativeMethods.EasyImpersonate(curl, "chrome142", 1); NativeMethods.EasySetOpt(curl, CurlOption.Nobody, (nint)1); // HEAD request var result = NativeMethods.EasyPerform(curl); CurlException.ThrowIfError(result); // Get HTTP response code NativeMethods.EasyGetInfoLong(curl, CurlInfo.ResponseCode, out long responseCode); Console.WriteLine($"Response Code: {responseCode}"); // Output: Response Code: 200 // Get total transfer time NativeMethods.EasyGetInfoDouble(curl, CurlInfo.TotalTime, out double totalTime); Console.WriteLine($"Total Time: {totalTime:F3}s"); // Output: Total Time: 0.234s // Get effective URL (after redirects) NativeMethods.EasyGetInfo(curl, CurlInfo.EffectiveUrl, out nint effectiveUrlPtr); var effectiveUrl = Marshal.PtrToStringAnsi(effectiveUrlPtr); Console.WriteLine($"Effective URL: {effectiveUrl}"); // Get timing breakdown NativeMethods.EasyGetInfoDouble(curl, CurlInfo.NameLookupTime, out double dnsTime); NativeMethods.EasyGetInfoDouble(curl, CurlInfo.ConnectTime, out double connectTime); NativeMethods.EasyGetInfoDouble(curl, CurlInfo.AppConnectTime, out double sslTime); Console.WriteLine($"DNS: {dnsTime:F3}s, TCP: {connectTime:F3}s, SSL: {sslTime:F3}s"); } finally { Marshal.FreeHGlobal(urlPtr); NativeMethods.EasyCleanup(curl); } ``` ## BrowserProfile Enumeration Provides strongly-typed browser profile selections with extension methods for conversion to curl-impersonate target strings. ```csharp using CurlImpersonate.Enums; // Chrome profiles (99, 100, 101, 104, 107, 110, 116, 119, 120, 123, 124, 131, 133a, 136, 142) var chrome = BrowserProfile.Chrome142; Console.WriteLine(chrome.ToTargetString()); // "chrome142" // Chrome Android profiles var chromeAndroid = BrowserProfile.Chrome131Android; Console.WriteLine(chromeAndroid.ToTargetString()); // "chrome131_android" // Safari profiles (15.3, 15.5, 17.0, 17.2 iOS, 18.0, 18.0 iOS, 18.4, 18.4 iOS, 26.0, 26.0.1, 26.0 iOS) var safari = BrowserProfile.Safari2601; Console.WriteLine(safari.ToTargetString()); // "safari2601" var safariIos = BrowserProfile.Safari260Ios; Console.WriteLine(safariIos.ToTargetString()); // "safari260_ios" // Firefox profiles (133, 135, 144) var firefox = BrowserProfile.Firefox144; Console.WriteLine(firefox.ToTargetString()); // "firefox144" // Edge profiles (99, 101) var edge = BrowserProfile.Edge101; Console.WriteLine(edge.ToTargetString()); // "edge101" // Tor Browser var tor = BrowserProfile.Tor145; Console.WriteLine(tor.ToTargetString()); // "tor145" // Get default profiles for each browser family Console.WriteLine(BrowserProfileExtensions.DefaultChrome); // Chrome142 Console.WriteLine(BrowserProfileExtensions.DefaultFirefox); // Firefox144 Console.WriteLine(BrowserProfileExtensions.DefaultSafari); // Safari2601 Console.WriteLine(BrowserProfileExtensions.DefaultSafariIos); // Safari260Ios Console.WriteLine(BrowserProfileExtensions.DefaultEdge); // Edge101 Console.WriteLine(BrowserProfileExtensions.DefaultTor); // Tor145 ``` ## WriteCallback and HeaderCallback Callback delegates for capturing response body and headers during transfers. ```csharp using System.Runtime.InteropServices; using System.Text; using CurlImpersonate.Enums; using CurlImpersonate.Native; nint curl = NativeMethods.EasyInit(); var urlPtr = Marshal.StringToHGlobalAnsi("https://httpbin.org/headers"); var responseBody = new StringBuilder(); var responseHeaders = new StringBuilder(); unsafe { // Write callback for response body WriteCallback writeCallback = (ptr, size, nmemb, userdata) => { var totalSize = size * nmemb; var data = new byte[totalSize]; Marshal.Copy((nint)ptr, data, 0, (int)totalSize); responseBody.Append(Encoding.UTF8.GetString(data)); return totalSize; }; // Header callback for response headers HeaderCallback headerCallback = (ptr, size, nmemb, userdata) => { var totalSize = size * nmemb; var data = new byte[totalSize]; Marshal.Copy((nint)ptr, data, 0, (int)totalSize); responseHeaders.Append(Encoding.UTF8.GetString(data)); return totalSize; }; var writePtr = Marshal.GetFunctionPointerForDelegate(writeCallback); var headerPtr = Marshal.GetFunctionPointerForDelegate(headerCallback); try { NativeMethods.EasySetOpt(curl, CurlOption.Url, urlPtr); NativeMethods.EasySetOpt(curl, CurlOption.WriteFunction, writePtr); NativeMethods.EasySetOpt(curl, CurlOption.HeaderFunction, headerPtr); NativeMethods.EasyImpersonate(curl, "chrome142", 1); var result = NativeMethods.EasyPerform(curl); CurlException.ThrowIfError(result); GC.KeepAlive(writeCallback); GC.KeepAlive(headerCallback); Console.WriteLine("=== Response Headers ==="); Console.WriteLine(responseHeaders); Console.WriteLine("=== Response Body ==="); Console.WriteLine(responseBody); } finally { Marshal.FreeHGlobal(urlPtr); NativeMethods.EasyCleanup(curl); } } ``` ## NativeMethods.MultiInit and Multi Handle Operations Creates and manages a curl multi handle for concurrent asynchronous transfers using event-driven I/O. ```csharp using System.Runtime.InteropServices; using CurlImpersonate.Enums; using CurlImpersonate.Native; // Create multi handle for concurrent requests nint multi = NativeMethods.MultiInit(); if (multi == 0) throw new Exception("Failed to create multi handle"); // Create multiple easy handles var urls = new[] { "https://httpbin.org/delay/1", "https://httpbin.org/delay/2", "https://httpbin.org/get" }; var handles = new List<nint>(); var urlPtrs = new List<nint>(); try { foreach (var url in urls) { nint easy = NativeMethods.EasyInit(); nint urlPtr = Marshal.StringToHGlobalAnsi(url); NativeMethods.EasySetOpt(easy, CurlOption.Url, urlPtr); NativeMethods.EasyImpersonate(easy, "chrome142", 1); // Add easy handle to multi var addResult = NativeMethods.MultiAddHandle(multi, easy); CurlMultiException.ThrowIfError(addResult, "Failed to add handle"); handles.Add(easy); urlPtrs.Add(urlPtr); } // Perform transfers int runningHandles; do { var performResult = NativeMethods.MultiPerform(multi, out runningHandles); CurlMultiException.ThrowIfError(performResult); if (runningHandles > 0) { // Wait for activity var waitResult = NativeMethods.MultiPoll(multi, 0, 0, 1000, out int numfds); CurlMultiException.ThrowIfError(waitResult); } } while (runningHandles > 0); Console.WriteLine($"All {handles.Count} requests completed"); } finally { // Cleanup: remove and cleanup all easy handles foreach (var easy in handles) { NativeMethods.MultiRemoveHandle(multi, easy); NativeMethods.EasyCleanup(easy); } foreach (var ptr in urlPtrs) { Marshal.FreeHGlobal(ptr); } NativeMethods.MultiCleanup(multi); } ``` ## NativeMethods.SlistAppend and SlistFreeAll Manages curl string lists for setting multiple HTTP headers. ```csharp using System.Runtime.InteropServices; using CurlImpersonate.Enums; using CurlImpersonate.Native; nint curl = NativeMethods.EasyInit(); var urlPtr = Marshal.StringToHGlobalAnsi("https://httpbin.org/headers"); nint headers = 0; try { // Build header list (returns new list pointer each time) headers = NativeMethods.SlistAppend(headers, "Accept: application/json"); headers = NativeMethods.SlistAppend(headers, "X-Custom-Header: custom-value"); headers = NativeMethods.SlistAppend(headers, "Authorization: Bearer token123"); headers = NativeMethods.SlistAppend(headers, "Cache-Control: no-cache"); if (headers == 0) throw new Exception("Failed to create header list"); NativeMethods.EasySetOpt(curl, CurlOption.Url, urlPtr); NativeMethods.EasySetOpt(curl, CurlOption.HttpHeader, headers); NativeMethods.EasyImpersonate(curl, "chrome142", 1); var result = NativeMethods.EasyPerform(curl); CurlException.ThrowIfError(result); } finally { // Free the header list if (headers != 0) NativeMethods.SlistFreeAll(headers); Marshal.FreeHGlobal(urlPtr); NativeMethods.EasyCleanup(curl); } ``` ## CurlException Error Handling Exception types for curl error handling with automatic error message lookup from native library. ```csharp using CurlImpersonate; using CurlImpersonate.Enums; using CurlImpersonate.Native; using System.Runtime.InteropServices; nint curl = NativeMethods.EasyInit(); try { // Set invalid URL to trigger error var urlPtr = Marshal.StringToHGlobalAnsi("invalid://not-a-url"); NativeMethods.EasySetOpt(curl, CurlOption.Url, urlPtr); Marshal.FreeHGlobal(urlPtr); var result = NativeMethods.EasyPerform(curl); // Option 1: Manual check if (result != CurlCode.Ok) { var message = CurlException.GetErrorMessage(result); Console.WriteLine($"Error {result}: {message}"); // Output: Error UnsupportedProtocol: Unsupported protocol } // Option 2: Throw helper CurlException.ThrowIfError(result); // Option 3: Throw helper with context CurlException.ThrowIfError(result, "HTTP request"); } catch (CurlException ex) { Console.WriteLine($"Curl error code: {ex.Code}"); Console.WriteLine($"Error message: {ex.Message}"); // Output: HTTP request: Unsupported protocol } finally { NativeMethods.EasyCleanup(curl); } // Multi handle error handling nint multi = NativeMethods.MultiInit(); try { var result = NativeMethods.MultiPerform(multi, out _); CurlMultiException.ThrowIfError(result, "Multi perform"); } catch (CurlMultiException ex) { Console.WriteLine($"Multi error code: {ex.Code}"); Console.WriteLine($"Error message: {ex.Message}"); } finally { NativeMethods.MultiCleanup(multi); } ``` ## SafeCurlHandle Safe handle wrapper for automatic resource cleanup using .NET's SafeHandle pattern. ```csharp using System.Runtime.InteropServices; using CurlImpersonate.Enums; using CurlImpersonate.Native; using CurlImpersonate.Native.SafeHandles; // Create a safe handle wrapper var handle = new SafeCurlHandle(NativeMethods.EasyInit(), ownsHandle: true); using (handle) { if (handle.IsInvalid) throw new Exception("Invalid curl handle"); var urlPtr = Marshal.StringToHGlobalAnsi("https://httpbin.org/get"); try { // Use DangerousGetHandle() when calling native methods NativeMethods.EasySetOpt(handle.DangerousGetHandle(), CurlOption.Url, urlPtr); NativeMethods.EasyImpersonate(handle.DangerousGetHandle(), "chrome142", 1); var result = NativeMethods.EasyPerform(handle.DangerousGetHandle()); CurlException.ThrowIfError(result); } finally { Marshal.FreeHGlobal(urlPtr); } } // Handle is automatically cleaned up when disposed ``` ## Complete Request with TLS Fingerprint Verification Full example demonstrating browser impersonation with fingerprint verification against a fingerprint testing service. ```csharp using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using CurlImpersonate.Enums; using CurlImpersonate.Native; static string PerformFingerprintRequest(BrowserProfile profile) { nint curl = NativeMethods.EasyInit(); var urlPtr = Marshal.StringToHGlobalAnsi("https://tls.browserleaks.com/json"); var responseData = new StringBuilder(); unsafe { WriteCallback writeCallback = (ptr, size, nmemb, userdata) => { var totalSize = size * nmemb; var data = new byte[totalSize]; Marshal.Copy((nint)ptr, data, 0, (int)totalSize); responseData.Append(Encoding.UTF8.GetString(data)); return totalSize; }; var callbackPtr = Marshal.GetFunctionPointerForDelegate(writeCallback); try { NativeMethods.EasySetOpt(curl, CurlOption.Url, urlPtr); // Enable browser impersonation NativeMethods.EasyImpersonate(curl, profile.ToTargetString(), 1); // Enable automatic decompression var acceptEncoding = Marshal.StringToHGlobalAnsi(""); NativeMethods.EasySetOpt(curl, CurlOption.AcceptEncoding, acceptEncoding); Marshal.FreeHGlobal(acceptEncoding); NativeMethods.EasySetOpt(curl, CurlOption.WriteFunction, callbackPtr); var result = NativeMethods.EasyPerform(curl); CurlException.ThrowIfError(result); GC.KeepAlive(writeCallback); return responseData.ToString(); } finally { Marshal.FreeHGlobal(urlPtr); NativeMethods.EasyCleanup(curl); } } } // Test different browser fingerprints var profiles = new[] { BrowserProfile.Chrome142, BrowserProfile.Firefox144, BrowserProfile.Safari2601, BrowserProfile.Edge101 }; foreach (var profile in profiles) { var response = PerformFingerprintRequest(profile); using var doc = JsonDocument.Parse(response); var root = doc.RootElement; Console.WriteLine($"Browser: {profile}"); Console.WriteLine($" JA3 Hash: {root.GetProperty("ja3_hash").GetString()}"); Console.WriteLine($" JA4: {root.GetProperty("ja4").GetString()}"); Console.WriteLine($" Akamai Hash: {root.GetProperty("akamai_hash").GetString()}"); Console.WriteLine(); } // Each browser produces unique, authentic fingerprints matching real browsers ``` CurlImpersonate.Net is primarily designed for web scraping, automated testing, and API integration scenarios where websites employ TLS fingerprinting to detect and block automated clients. By impersonating real browser fingerprints, applications can access content that would otherwise be blocked, making it valuable for data collection, price monitoring, content aggregation, and testing bot-protection systems. The library's low-level P/Invoke design provides maximum flexibility while maintaining compatibility with curl-impersonate's full feature set. Integration with existing .NET applications is straightforward as the library follows standard patterns for native interop. For high-throughput scenarios, the multi-handle interface enables concurrent requests with event-driven I/O. The library supports all major platforms (Windows x64/ARM64, Linux x64/ARM64, macOS x64/ARM64) with native libraries bundled for each runtime. Consider wrapping the low-level APIs in higher-level abstractions for production use, implementing proper connection pooling, retry logic, and response caching as needed for your specific use case.