Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To keep cookies between C# HttpClient requests, create a CookieContainer, assign it to the HttpClientHandler.CookieContainer property, leave UseCookies enabled, and reuse the resulting handler (and client) for the requests that belong to the same session.

Microsoft documents that the container is associated with the handler. The handler stores cookies received from responses and supplies applicable cookies on later requests. UseCookies is documented as true by default, but setting it explicitly makes your intent clear.

Configure a cookie-enabled HttpClient

This is the complete pattern for automatic cookie storage and replay:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

var cookies = new CookieContainer();
var handler = new HttpClientHandler
{
    CookieContainer = cookies,
    UseCookies = true
};

using var client = new HttpClient(handler);

using var response1 = await client.GetAsync("https://example.com/login-or-start");
response1.EnsureSuccessStatusCode();

using var response2 = await client.GetAsync("https://example.com/account");
response2.EnsureSuccessStatusCode();

The same handler owns the same CookieContainer, so cookies accepted while processing response1 are available when response2 is sent. Creating a new handler or container for every request creates a new cookie state instead of continuing the session.

For API details, see HttpClientHandler.CookieContainer and HttpClientHandler.UseCookies.

Add a cookie before the first request

Seed the container with a cookie for the URI and domain where it should apply:

using System;
using System.Net;
using System.Net.Http;

var cookies = new CookieContainer();
cookies.Add(
    new Uri("https://example.com/"),
    new Cookie("session", "value"));

var handler = new HttpClientHandler
{
    CookieContainer = cookies,
    UseCookies = true
};

using var client = new HttpClient(handler);
using var response = await client.GetAsync("https://example.com/account");
response.EnsureSuccessStatusCode();

The URI passed to Add determines where the cookie is applicable. Use the correct scheme, host, path, and (when relevant) port for the server that must receive it. A cookie for one host should not be assumed to apply to another host.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Understand the session boundary

Reuse state for one logical session

A cookie container is session state. Keep the handler and its container alive for all requests that represent one login or browsing session. In a small console program, that commonly means creating them once in Main and disposing the client when the operation finishes.

Isolate users and tenants

Because the container belongs to the handler, sharing one handler across unrelated users also shares cookie state. Give each independent session its own container and handler. This prevents one session’s server-issued cookies from being offered to another session.

Do not recreate the client per request

Constructing a fresh HttpClientHandler and CookieContainer for every call loses cookies collected by earlier responses. Reuse the configured pair for the intended scope instead.

How automatic cookie handling works

  1. The server sends a cookie in an HTTP response.
  2. The handler processes that response and stores the cookie in its CookieContainer when automatic cookie handling is enabled.
  3. On a later request, the handler selects applicable stored cookies and sends them automatically.

This behavior is controlled by UseCookies. Microsoft documents its default as true. Setting it to false disables this automatic mechanism: cookies in the assigned container are ignored by the handler and server cookies are not automatically retained for later requests.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When UseCookies is false

Some applications deliberately disable automatic handling because they want to own cookie processing themselves. In that mode, do not expect a populated CookieContainer to be sent automatically. You must implement a deliberate application-managed approach appropriate to your protocol and security requirements; this article does not prescribe manual header composition.

Inspect cookies while diagnosing a session

If you need to verify what the handler has stored, query the container for a URI:

var stored = cookies.GetCookies(new Uri("https://example.com/"));
foreach (Cookie cookie in stored)
{
    Console.WriteLine($"{cookie.Name}={cookie.Value}; Domain={cookie.Domain}; Path={cookie.Path}");
}

Inspection is useful for confirming that a login response set a cookie and that its domain and path match the request you intend to make. Avoid writing session values to production logs; cookies can be credentials.

Posting login credentials, then using the session

The cookie setup is independent of the request method. For a form login, send the form through the same client, then issue subsequent requests through that client:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
using System.Collections.Generic;
using System.Net;
using System.Net.Http;

var cookies = new CookieContainer();
var handler = new HttpClientHandler
{
    CookieContainer = cookies,
    UseCookies = true
};

using var client = new HttpClient(handler)
{
    BaseAddress = new Uri("https://example.com/")
};

using var login = await client.PostAsync(
    "login",
    new FormUrlEncodedContent(new Dictionary<string, string>
    {
        ["username"] = "alice",
        ["password"] = "replace-with-secret"
    }));
login.EnsureSuccessStatusCode();

using var privatePage = await client.GetAsync("account");
privatePage.EnsureSuccessStatusCode();

The server must actually issue a cookie that is valid for the later URI. A successful status code alone does not prove that authentication state was established, so inspect the response and container when troubleshooting.

Framework and implementation notes

The public APIs apply across .NET, .NET Framework, and .NET Standard families, but the underlying implementation differs by target. Microsoft notes that the HTTP stack moved to a SocketsHttpHandler-based cross-platform implementation beginning with .NET Core 2.1. Check the API documentation for your target framework and platform, especially when behavior differs between an older .NET Framework application and a current .NET release. The current reference pages include applicability tables extending through newer .NET versions.

Security and correctness checklist

  • Use HTTPS for requests carrying authentication or session cookies.
  • Keep cookie containers scoped to the intended user or service session.
  • Never commit real cookie values or passwords to source control.
  • Redact cookie values from logs and diagnostic output.
  • Use the exact origin URI when seeding a cookie so domain and path matching work as intended.
  • Dispose the client and handler when their session is finished, using using statements or an equivalent lifetime strategy.

Troubleshooting common failures

The second request is unauthenticated

  • Cause: a new handler or container was created for the second request.
  • Fix: create one configured pair and reuse it for both requests.
  • Check: inspect cookies.GetCookies(uri) after the first response.

The container is populated, but no cookie is sent

  • Cause: UseCookies is false, or the cookie’s domain/path does not match the destination.
  • Fix: enable UseCookies and seed the cookie against the correct URI; verify the stored cookie’s properties.

A cookie is not retained after login

  • Cause: the response did not set a usable cookie for the later request, or the request went to a different host or path.
  • Fix: examine the response and container, then compare the cookie’s domain/path with the next request URI.

Different users appear to share a login

  • Cause: they share a handler and therefore a container.
  • Fix: allocate separate cookie state per independent session.

Behavior changes after upgrading .NET

Confirm the target framework and platform against the HttpClientHandler documentation. The implementation transition beginning with .NET Core 2.1 means older and newer targets can use different underlying stacks even though the API shape is similar.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance and reliability considerations

Cookie handling itself is lightweight compared with loading a remote response, but session correctness depends on stable handler lifetime. Reuse the configured client for related calls rather than rebuilding it repeatedly. At the same time, do not use one cookie container as a global store for unrelated users. If a long-running application manages many sessions, design an explicit lifetime and cleanup policy for those handlers and containers.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cookie state is not a substitute for retry policy, authentication-token management, or server-side session expiration. If the server expires a session, the client must follow the server’s authentication flow again.

Or skip the browser setup

If your goal is a clean image or PDF of a website rather than an authenticated application session, ScreenshotNeo provides a single HTTP call instead of building browser automation. Its API accepts a URL and can return PNG, JPEG, WebP, or PDF. Before capture it accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.

For a direct call, see the ScreenshotNeo API documentation:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same endpoint can be called from C# with HttpClient:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
using var http = new HttpClient();
var query = "https://api.screenshotneo.com/v1/shot" +
            "?access_key=YOUR_API_KEY" +
            "&url=https%3A%2F%2Fstripe.com";
var bytes = await http.GetByteArrayAsync(query);
await File.WriteAllBytesAsync("shot.webp", bytes);

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Every feature is included on every plan. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to get started.

Frequently Asked Questions

Can I share one CookieContainer between multiple HttpClient instances?

Yes, but doing so intentionally shares cookie state. Use that only when the clients belong to the same logical session; isolate unrelated users or tenants.

Does HttpClient automatically preserve cookies without extra configuration?

Only when its handler uses automatic cookie handling. Configure the handler’s CookieContainer and keep the handler alive across the requests that need shared state.

Why does a cookie work for one URL but not another?

Cookie domain and path rules determine applicability. Verify the stored cookie properties and compare them with the destination URI.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.