PhantomClient 1.0.9

dotnet add package PhantomClient --version 1.0.9
                    
NuGet\Install-Package PhantomClient -Version 1.0.9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PhantomClient" Version="1.0.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PhantomClient" Version="1.0.9" />
                    
Directory.Packages.props
<PackageReference Include="PhantomClient" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PhantomClient --version 1.0.9
                    
#r "nuget: PhantomClient, 1.0.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PhantomClient@1.0.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PhantomClient&version=1.0.9
                    
Install as a Cake Addin
#tool nuget:?package=PhantomClient&version=1.0.9
                    
Install as a Cake Tool

PhantomClient

A stealth HTTP client library for .NET that can bypass Cloudflare and most TLS handshake security measures by leveraging advanced TLS fingerprinting capabilities.

What is PhantomClient?

PhantomClient is a .NET 9.0 library that enables you to make HTTP requests that closely mimic real browsers by replicating their TLS fingerprints, making it ideal for:

  • Web scraping protected sites
  • API testing with anti-bot protection
  • Automated testing of sites with Cloudflare or similar protection
  • Bypassing TLS fingerprinting detection

Features

  • ✅ Multiple browser fingerprint profiles (Chrome, Firefox, Safari, etc.)
  • ✅ Support for all HTTP methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)
  • ✅ Automatic cookie management and persistence per client instance
  • ✅ Proxy support (HTTP, SOCKS5)
  • ✅ Custom timeout configuration
  • ✅ Header order preservation
  • ✅ Form data and JSON body support
  • ✅ Easy-to-use async/await API
  • ✅ Built on .NET 9.0 with modern C# practices

Installation

NuGet Package Manager

dotnet add package PhantomClient

Package Manager Console

Install-Package PhantomClient

Prerequisites

  • .NET 9.0 SDK or later
  • Node.js (v14 or later) installed on the system

Quick Start

using PhantomClientCore;

// Initialize the TLS service once at application start
await PhantomTLS.InitializeAsync();

// Create a new client instance
using var client = new PhantomClient();

// Make a simple GET request
var response = await client.GetAsync("https://example.com");

Console.WriteLine($"Status: {response.Status}");
Console.WriteLine($"Body: {response.Body}");

// Clean up when done (optional, at program exit)
await PhantomTLS.DestroyAsync();

Usage Scenarios

Scenario 1: Simple GET Request with Custom Headers

using PhantomClientCore;

// Initialize once
await PhantomTLS.InitializeAsync();

using var client = new PhantomClient(new PhantomClientOptions
{
    ClientIdentifier = "chrome_120",
    Timeout = 30000
});

var response = await client.GetAsync("https://api.example.com/data", new RequestOptions
{
    Headers = new Dictionary<string, string>
    {
        ["Accept"] = "application/json",
        ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0",
        ["Accept-Language"] = "en-US,en;q=0.9"
    }
});

if (response.IsSuccess)
{
    Console.WriteLine($"Success: {response.Body}");
}

await PhantomTLS.DestroyAsync();

Scenario 2: POST Request with JSON Data

using PhantomClientCore;
using System.Text.Json;

await PhantomTLS.InitializeAsync();

using var client = new PhantomClient();

var payload = new { username = "testuser", password = "secret123" };
var jsonBody = JsonSerializer.Serialize(payload);

var response = await client.PostAsync("https://api.example.com/login", new PostRequestOptions
{
    Body = jsonBody,
    Headers = new Dictionary<string, string>
    {
        ["Content-Type"] = "application/json",
        ["Accept"] = "application/json"
    }
});

Console.WriteLine($"Response: {response.Body}");

await PhantomTLS.DestroyAsync();

Scenario 3: POST Request with Form Data

using PhantomClientCore;

await PhantomTLS.InitializeAsync();

using var client = new PhantomClient();

var formData = new Dictionary<string, string>
{
    ["username"] = "testuser",
    ["password"] = "secret123",
    ["remember"] = "true"
};

var response = await client.PostFormAsync("https://example.com/login", formData);

if (response.IsSuccess)
{
    Console.WriteLine("Login successful!");
}

await PhantomTLS.DestroyAsync();

Scenario 4: Bypassing Cloudflare Protection

using PhantomClientCore;

await PhantomTLS.InitializeAsync();

using var client = new PhantomClient(new PhantomClientOptions
{
    ClientIdentifier = "chrome_120", // Use latest Chrome fingerprint
    Timeout = 30000
});

var response = await client.GetAsync("https://cloudflare-protected-site.com", new RequestOptions
{
    Headers = new Dictionary<string, string>
    {
        ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0",
        ["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        ["Accept-Language"] = "en-US,en;q=0.9",
        ["Accept-Encoding"] = "gzip, deflate, br",
        ["Sec-Fetch-Dest"] = "document",
        ["Sec-Fetch-Mode"] = "navigate",
        ["Sec-Fetch-Site"] = "none"
    }
});

if (response.IsSuccess)
{
    Console.WriteLine("Successfully bypassed protection!");

    // Cookies are automatically stored in the client instance
    var cookies = client.Cookies.GetCookies("https://cloudflare-protected-site.com");
    foreach (var cookie in cookies)
    {
        Console.WriteLine($"{cookie.Key}: {cookie.Value}");
    }
}

await PhantomTLS.DestroyAsync();

Scenario 5: Session Management with Cookies

using PhantomClientCore;

await PhantomTLS.InitializeAsync();

using var client = new PhantomClient();

// First request - Login and capture cookies
var loginResponse = await client.PostFormAsync("https://example.com/login",
    new Dictionary<string, string>
    {
        ["username"] = "user",
        ["password"] = "pass"
    });

Console.WriteLine($"Login status: {loginResponse.Status}");

// Cookies are automatically stored in the client instance
// and will be sent with subsequent requests

// Second request - Use stored cookies automatically
var profileResponse = await client.GetAsync("https://example.com/profile");
Console.WriteLine($"Profile data: {profileResponse.Body}");

// Get all cookies for a domain
var cookies = client.Cookies.GetCookies("https://example.com");
foreach (var cookie in cookies)
{
    Console.WriteLine($"{cookie.Key}: {cookie.Value}");
}

// Clear cookies for a specific domain
client.Cookies.ClearCookies("https://example.com");

await PhantomTLS.DestroyAsync();

Scenario 6: Using Proxy

using PhantomClientCore;

await PhantomTLS.InitializeAsync();

// Configure client with proxy
using var client = new PhantomClient(new PhantomClientOptions
{
    ClientIdentifier = "chrome_120",
    Proxy = "http://username:password@proxy.example.com:8080",
    Timeout = 30000
});

var response = await client.GetAsync("https://api.ipify.org?format=json");
Console.WriteLine($"Response via proxy: {response.Body}");

// You can also override proxy per request
var response2 = await client.GetAsync("https://example.com", new RequestOptions
{
    Proxy = "http://different-proxy.com:8080"
});

await PhantomTLS.DestroyAsync();

Scenario 7: Multiple Isolated Client Instances

Each PhantomClient instance maintains its own cookies and session:

using PhantomClientCore;

await PhantomTLS.InitializeAsync();

// Create two separate clients with different configurations
using var client1 = new PhantomClient(new PhantomClientOptions
{
    ClientIdentifier = "chrome_103"
});

using var client2 = new PhantomClient(new PhantomClientOptions
{
    ClientIdentifier = "firefox_120"
});

// Set cookies in client1
await client1.GetAsync("https://httpbin.org/cookies/set?session=abc123");

// client2 has its own isolated cookie container
var client1Cookies = client1.Cookies.GetCookies("https://httpbin.org");
var client2Cookies = client2.Cookies.GetCookies("https://httpbin.org");

Console.WriteLine($"Client1 cookies: {client1Cookies.Count}"); // Has cookies
Console.WriteLine($"Client2 cookies: {client2Cookies.Count}"); // Empty (isolated)

await PhantomTLS.DestroyAsync();

Scenario 8: All HTTP Methods

using PhantomClientCore;

await PhantomTLS.InitializeAsync();

using var client = new PhantomClient();

// GET request
var getResponse = await client.GetAsync("https://httpbin.org/get");

// POST request
var postResponse = await client.PostAsync("https://httpbin.org/post",
    new PostRequestOptions { Body = "{\"data\":\"value\"}" });

// PUT request
var putResponse = await client.PutAsync("https://httpbin.org/put",
    new PostRequestOptions { Body = "{\"update\":\"value\"}" });

// DELETE request
var deleteResponse = await client.DeleteAsync("https://httpbin.org/delete");

// PATCH request
var patchResponse = await client.PatchAsync("https://httpbin.org/patch",
    new PostRequestOptions { Body = "{\"field\":\"value\"}" });

// HEAD request (no body in response)
var headResponse = await client.HeadAsync("https://httpbin.org/get");

// OPTIONS request
var optionsResponse = await client.OptionsAsync("https://httpbin.org/get");

await PhantomTLS.DestroyAsync();

Scenario 9: Redirect Handling

using PhantomClientCore;

await PhantomTLS.InitializeAsync();

using var client = new PhantomClient();

// Follow redirects (default behavior)
var response1 = await client.GetAsync("https://httpbin.org/redirect/2");
Console.WriteLine($"Final URL: {response1.Url}"); // Shows final URL after redirects

// Don't follow redirects
var response2 = await client.GetAsync("https://httpbin.org/redirect/1", new RequestOptions
{
    FollowRedirect = false
});
Console.WriteLine($"Status: {response2.Status}"); // Will be 302 or similar

await PhantomTLS.DestroyAsync();

Scenario 10: Error Handling and Retries

using PhantomClientCore;

await PhantomTLS.InitializeAsync();

using var client = new PhantomClient(new PhantomClientOptions
{
    ClientIdentifier = "chrome_120",
    Timeout = 15000
});

async Task<TlsResponse?> MakeRequestWithRetry(string url, int maxRetries = 3)
{
    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            var response = await client.GetAsync(url);

            if (response.IsSuccess)
                return response;

            Console.WriteLine($"Attempt {i + 1} failed with status: {response.Status}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Attempt {i + 1} error: {ex.Message}");
        }

        await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i))); // Exponential backoff
    }

    return null;
}

var result = await MakeRequestWithRetry("https://example.com");
if (result != null)
{
    Console.WriteLine("Success!");
}

await PhantomTLS.DestroyAsync();

API Reference

PhantomTLS Class (Static)

Methods
  • static Task InitializeAsync()

    • Initializes the TlsService. Must be called before using the library.
  • static Task DestroyAsync()

    • Cleans up the TlsService service. Optional, typically called at program exit.

PhantomClient Class

Constructor
public PhantomClient(PhantomClientOptions? options = null)

Creates a new client instance. Each instance maintains its own session and cookies.

Properties
  • CookieContainer Cookies { get; }
    • Cookie container for automatic cookie management
Methods
  • Task<TlsResponse> GetAsync(string url, RequestOptions? options = null)

    • Makes an HTTP GET request
  • Task<TlsResponse> PostAsync(string url, PostRequestOptions? options = null)

    • Makes an HTTP POST request with JSON or raw body
  • Task<TlsResponse> PostFormAsync(string url, Dictionary<string, string> formData, RequestOptions? options = null)

    • Makes an HTTP POST request with form data (application/x-www-form-urlencoded)
  • Task<TlsResponse> PutAsync(string url, PostRequestOptions? options = null)

    • Makes an HTTP PUT request
  • Task<TlsResponse> PatchAsync(string url, PostRequestOptions? options = null)

    • Makes an HTTP PATCH request
  • Task<TlsResponse> DeleteAsync(string url, RequestOptions? options = null)

    • Makes an HTTP DELETE request
  • Task<TlsResponse> HeadAsync(string url, RequestOptions? options = null)

    • Makes an HTTP HEAD request
  • Task<TlsResponse> OptionsAsync(string url, RequestOptions? options = null)

    • Makes an HTTP OPTIONS request

PhantomClientOptions Class

public class PhantomClientOptions
{
    public string ClientIdentifier { get; set; } = "chrome_103";
    public int Timeout { get; set; } = 30000;
    public string? Proxy { get; set; }
    public Dictionary<string, string>? DefaultHeaders { get; set; }
    public bool InsecureSkipVerify { get; set; } = false;
}

RequestOptions Class

public class RequestOptions
{
    public Dictionary<string, string>? Headers { get; set; }
    public Dictionary<string, string>? Cookies { get; set; }
    public bool FollowRedirect { get; set; } = true;
    public string? Proxy { get; set; }
}

PostRequestOptions Class

public class PostRequestOptions : RequestOptions
{
    public string? Body { get; set; }
    public Dictionary<string, string>? FormData { get; set; }
}

TlsResponse Class

public class TlsResponse
{
    public int Status { get; set; }
    public string StatusText { get; set; }
    public Dictionary<string, string> Headers { get; set; }
    public string Body { get; set; }
    public Dictionary<string, string> Cookies { get; set; }
    public string Url { get; set; }
    public bool IsSuccess { get; } // true if status 200-299
}

CookieContainer Class

Methods
  • Dictionary<string, string> GetCookies(string url)

    • Retrieves cookies for a specific URL/domain
  • void ClearCookies(string url)

    • Clears cookies for a specific URL/domain

Available Browser Fingerprints

PhantomClient supports multiple browser fingerprints via the ClientIdentifier property:

Chrome

  • chrome_103, chrome_104, chrome_105, chrome_106, chrome_107
  • chrome_108, chrome_109, chrome_110, chrome_111, chrome_112
  • chrome_116_PSK, chrome_116_PSK_PQ, chrome_117, chrome_120

Firefox

  • firefox_102, firefox_104, firefox_105, firefox_106
  • firefox_108, firefox_110, firefox_117, firefox_120

Safari

  • safari_15_6_1, safari_16_0
  • safari_ipad_15_6, safari_ios_15_5, safari_ios_15_6, safari_ios_16_0

Other

  • opera_89, opera_90
  • zalando_android_mobile, nike_ios_mobile, mesh_ios, mesh_android

Best Practices

  1. Initialize once: Call PhantomTLS.InitializeAsync() once at application start
  2. Reuse client instances: Create one PhantomClient instance and reuse it for multiple requests
  3. Dispose properly: Always use using statements or call Dispose() when done
  4. Match headers to fingerprint: Use realistic headers that match your chosen browser fingerprint
  5. Respect rate limits: Add delays between requests to avoid detection
  6. Handle cookies: Each client instance automatically manages cookies - use separate instances for isolated sessions

Troubleshooting

"Node.js not found" error

  • Ensure Node.js is installed and available in your system PATH
  • Verify installation: node --version

Timeout errors

  • Increase Timeout in PhantomClientOptions
  • Check your network connection and proxy settings
  • Remember that each PhantomClient instance has its own cookie container
  • Use client.Cookies.GetCookies(url) to inspect stored cookies

License

MIT License - Copyright © 2025 Riadh Chebbi. All rights reserved.

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

Disclaimer

This library is intended for legitimate purposes such as testing, research, and automation of your own services. Always respect websites' Terms of Service and robots.txt files. The authors are not responsible for misuse of this library.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.9 109 10/11/2025
1.0.8 103 10/11/2025
1.0.7 109 10/11/2025
1.0.5 93 10/11/2025
1.0.4 90 10/10/2025
1.0.3 88 10/10/2025
1.0.2 90 10/10/2025
1.0.1 93 10/10/2025