Skip to the content.

How to set curl custom headers and User-Agent in C#

To set custom headers in C# the curl way, repeat -H "Name: value" in the command you pass to Curl.ExecuteAsync; use -A for the User-Agent, -e for the Referer and -b for cookies. The fluent builder has WithHeader, WithUserAgent, WithReferer and WithCookie.

dotnet add package CurlDotNet

The curl command

using CurlDotNet;

var result = await Curl.ExecuteAsync("""
    curl https://httpbin.org/headers \
      -H "Accept: application/json" \
      -H "X-Api-Key: my-key" \
      -A "MyApp/1.0" \
      -e "https://example.com/start"
    """);

Console.WriteLine(result.Body);  // httpbin echoes the headers it received

Set a User-Agent: curl’s defaults apply until you do

Like the curl CLI, CurlDotNet sends User-Agent: curl/8.7.1 (Curl.DefaultUserAgent) and Accept: */* on every request, so APIs that insist on a User-Agent, such as GitHub’s REST API, work without any extra flag. Use -A to identify your own app:

using CurlDotNet;

var result = await Curl.ExecuteAsync(
    "curl -A 'my-app/1.0' https://api.github.com/repos/jacob-mellor/curl-dot-net");

Console.WriteLine(result.StatusCode);  // 200 (also 200 without -A)

The other header rules match curl:

You write Sent
-A '' No User-Agent header
-H 'User-Agent:' or -H 'Accept:' Removes that default header
-H 'X-Empty;' X-Empty: with an empty value
-H @headers.txt One header per line from the file
-H 'X-A: 1' -H 'X-A: 2' X-A: 1, 2

The fluent builder

using CurlDotNet.Core;

var result = await CurlRequestBuilder
    .Get("https://httpbin.org/headers")
    .WithHeader("Accept", "application/json")
    .WithHeaders(new Dictionary<string, string> { ["X-Api-Key"] = "my-key" })
    .WithUserAgent("MyApp/1.0")
    .WithReferer("https://example.com/start")
    .ExecuteAsync();

Send cookies

-b takes a cookie string (name=value; name2=value2):

using CurlDotNet;

var result = await Curl.ExecuteAsync(
    "curl -b 'session=abc; theme=dark' https://httpbin.org/cookies");

Console.WriteLine(result.Body);  // {"cookies": {"session": "abc", "theme": "dark"}}

The builder equivalent is .WithCookie("session=abc; theme=dark"). Repeated -b strings are joined with "; ".

Cookie files work like the curl CLI: -c cookies.txt writes the cookies the server sets to a Netscape-format jar, and -b cookies.txt (a value without =) reads them back on the next run. With either one, cookies set during a redirect chain are sent on the following hops:

using CurlDotNet;

await Curl.ExecuteAsync("curl -c cookies.txt https://httpbin.org/cookies/set?session=abc");
var result = await Curl.ExecuteAsync("curl -b cookies.txt https://httpbin.org/cookies");

Console.WriteLine(result.Body);  // {"cookies": {"session": "abc"}}

Read response headers

result.Headers is a case-insensitive dictionary that holds both response and content headers. Multi-value headers are joined with ", ".

using CurlDotNet;

var result = await Curl.ExecuteAsync("curl https://httpbin.org/json");

Console.WriteLine(result.Headers["content-type"]);     // application/json
Console.WriteLine(result.GetHeader("Content-Length"));
Console.WriteLine(result.HasHeader("ETag"));

-i also puts the status line and headers at the start of result.Body, as the CLI prints them.

Default headers for every request

LibCurl keeps defaults that it merges into each call:

using CurlDotNet.Lib;

using var curl = new LibCurl();
curl.WithUserAgent("MyApp/1.0").WithHeader("X-Api-Key", "my-key");
var result = await curl.GetAsync("https://httpbin.org/headers");