Xquik C# SDK: Twitter search, followers & X automation

August 21, 2026 ยท View on GitHub

OpenSSF Best Practices CI

Use the Xquik C# SDK for Twitter search, timelines, profiles, and followers. Download media, manage webhooks, and run X automation from .NET.

C# client or REST

The typed NuGet package calls the documented Xquik REST API. It does not call or emulate the official X API. Use the SDK for asynchronous, typed requests from .NET services. Reuse the configurable HttpClient for shared transport settings. Call REST directly when a NuGet dependency does not fit.

Read the C# SDK guide or API guide.

Common X data tasks

TaskREST routeWorkflow note
Search tweetsGET /x/tweets/searchUse keywords or advanced Twitter search operators.
Extract profile tweetsGET /x/users/{id}/tweetsPaginate bounded timeline results.
Export followersGET /x/users/{id}/followersUse an extraction for complete datasets.
Export following accountsGET /x/users/{id}/followingUse an extraction for complete datasets.
Read a home timelineGET /x/timelineApprove this private read.
Read lists or communities/x/lists/*, /x/communities/*Use the typed nested services.
Export large datasetsPOST /extractionsPoll status, then download results.
Monitor an accountPOST /monitorsDeliver events through HMAC webhooks.
Post or replyPOST /x/tweetsConfirm the account and payload.

Installation

Requires .NET Standard 2.0 or later.

Install the package from NuGet:

dotnet add package XTwitterScraper --version 0.6.2

Verify a release

Verify a GitHub release package before using it:

release_tag=vVERSION
package_version="${release_tag#v}"

gh release download "$release_tag" \
  --repo Xquik-dev/x-twitter-scraper-csharp \
  --pattern "XTwitterScraper.$package_version.nupkg"

gh attestation verify "XTwitterScraper.$package_version.nupkg" \
  --repo Xquik-dev/x-twitter-scraper-csharp \
  --signer-workflow Xquik-dev/x-twitter-scraper-csharp/.github/workflows/publish-nuget.yml \
  --source-ref "refs/tags/$release_tag" \
  --deny-self-hosted-runners

Require the Xquik-dev repository and expected release workflow.

GitHub verifies the artifact digest, signer identity, and transparency proof.

NuGet.org applies repository signatures to registry packages.

Usage

using System;
using XTwitterScraper;
using XTwitterScraper.Models.X.Tweets;

XTwitterScraperClient client = new();

TweetSearchParams parameters = new()
{
    Q = "from:elonmusk",
    Limit = 10,
};

var paginatedTweets = await client.X.Tweets.Search(parameters);

Console.WriteLine(paginatedTweets);

Client configuration

Configure the client using environment variables:

using XTwitterScraper;

// Reads API key, bearer token, and base URL environment variables.
XTwitterScraperClient client = new();

Set credentials directly when environment variables do not fit:

using XTwitterScraper;

XTwitterScraperClient client = new()
{
    ApiKey = "My API Key",
    BearerToken = "My Bearer Token",
};

Environment variables and explicit properties can be combined.

PropertyEnvironment variableRequiredDefault value
ApiKeyX_TWITTER_SCRAPER_API_KEYfalse-
BearerTokenX_TWITTER_SCRAPER_BEARER_TOKENfalse-
BaseUrlX_TWITTER_SCRAPER_BASE_URLtrue"https://xquik.com/api/v1"

Modify configuration

Call WithOptions to reuse connections with temporary settings:

using System;

var account = await client
    .WithOptions(options =>
        options with
        {
            BaseUrl = "https://example.com",
            Timeout = TimeSpan.FromSeconds(42),
        }
    )
    .Account.Retrieve(parameters);

Console.WriteLine(account);

The with expression builds the modified options. WithOptions leaves the original client or service unchanged.

Requests & responses

client.X.Tweets.Search accepts TweetSearchParams and returns Task<PaginatedTweets>.

Binary responses

Binary endpoints return HttpResponse instead of parsing the body:

using System;
using XTwitterScraper.Models.Extractions;

ExtractionExportResultsParams parameters = new()
{
    ID = "id",
    Format = Format.Csv,
};

var response = await client.Extractions.ExportResults(parameters);

Console.WriteLine(response);

Use CopyToAsync to save content to any Stream:

using System.IO;

using var response = await client.Extractions.ExportResults(parameters);
using var contentStream = await response.ReadAsStream();
using var fileStream = File.Open(path, FileMode.Create);
await contentStream.CopyToAsync(fileStream); // Accepts any Stream.

Raw responses

Typed methods hide headers, status codes, and raw bodies. Prefix any HTTP call with WithRawResponse to access them:

var response = await client.WithRawResponse.Account.Retrieve();
var statusCode = response.StatusCode;
var headers = response.Headers;

Access the raw HttpResponseMessage through RawMessage. Deserialize non-streaming responses when you need a typed model:

using System;
using XTwitterScraper.Models.Account;

var response = await client.WithRawResponse.Account.Retrieve();
AccountRetrieveResponse deserialized = await response.Deserialize();
Console.WriteLine(deserialized);

Error handling

API errors inherit from XTwitterScraperApiException:

StatusException
400XTwitterScraperBadRequestException
401XTwitterScraperUnauthorizedException
403XTwitterScraperForbiddenException
404XTwitterScraperNotFoundException
422XTwitterScraperUnprocessableEntityException
429XTwitterScraperRateLimitException
5xxXTwitterScraper5xxException
othersXTwitterScraperUnexpectedStatusCodeException

All 4xx errors inherit from XTwitterScraper4xxException. Networking errors use XTwitterScraperIOException. Invalid response data uses XTwitterScraperInvalidDataException. Every SDK exception inherits from XTwitterScraperException.

Retries

The SDK retries these errors twice with exponential backoff:

  • Connection errors
  • 408 Request Timeout
  • 409 Conflict
  • 429 Rate Limit
  • 5xx server errors

The API may override retry behavior.

Set MaxRetries on the client:

using XTwitterScraper;

XTwitterScraperClient client = new() { MaxRetries = 3 };

Override retries for one call with WithOptions:

using System;

var account = await client
    .WithOptions(options =>
        options with { MaxRetries = 3 }
    )
    .Account.Retrieve(parameters);

Console.WriteLine(account);

Timeouts

Requests time out after 1 minute by default.

Set Timeout on the client:

using System;
using XTwitterScraper;

XTwitterScraperClient client = new() { Timeout = TimeSpan.FromSeconds(42) };

Override the timeout for one call with WithOptions:

using System;

var account = await client
    .WithOptions(options =>
        options with { Timeout = TimeSpan.FromSeconds(42) }
    )
    .Account.Retrieve(parameters);

Console.WriteLine(account);

Proxies

Route requests through a custom HttpClient:

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

var httpClient = new HttpClient
(
    new HttpClientHandler
    {
        Proxy = new WebProxy("https://example.com:8080")
    }
);

XTwitterScraperClient client = new() { HttpClient = httpClient };

Custom API fields

The SDK accepts API fields missing from its generated types.

Request fields

Pass dictionaries for extra header, query, and body values. Methods without request bodies accept only header and query dictionaries.

using System.Collections.Generic;
using System.Text.Json;
using XTwitterScraper.Models.X.Tweets;

TweetSearchParams parameters = new
(
    rawHeaderData: new Dictionary<string, JsonElement>()
    {
        { "Custom-Header", JsonSerializer.SerializeToElement(42) }
    },

    rawQueryData: new Dictionary<string, JsonElement>()
    {
        { "custom_query_param", JsonSerializer.SerializeToElement(42) }
    }
)
{
    // Documented values override matching custom parameters.
    Limit = 200
};

Access raw values through RawHeaderData, RawQueryData, and RawBodyData. Use FromRawUnchecked for unsupported values in required parameters:

using System.Collections.Generic;
using System.Text.Json;
using XTwitterScraper.Models.X.Tweets;

var parameters = TweetSearchParams.FromRawUnchecked
(

    rawHeaderData: new Dictionary<string, JsonElement>(),
    rawQueryData: new Dictionary<string, JsonElement>
    {
        {
            "q",
            JsonSerializer.SerializeToElement("custom value")
        }
    }
);

Response properties

Read undocumented response properties through RawData:

using System.Text.Json;

var response = await client.X.Tweets.Search(parameters);
if (response.RawData.TryGetValue("my_custom_key", out JsonElement value))
{
    // Process value.
}

RawData contains the complete response as IReadOnlyDictionary<string, JsonElement>.

Response validation

Unexpected response values throw only when you access their properties. Call Validate to check the complete response immediately:

var paginatedTweets = await client.X.Tweets.Search(parameters);
paginatedTweets.Validate();

Set ResponseValidation to validate every response:

using XTwitterScraper;

XTwitterScraperClient client = new() { ResponseValidation = true };

Validate one call with WithOptions:

using System;

var paginatedTweets = await client
    .WithOptions(options =>
        options with { ResponseValidation = true }
    )
    .X.Tweets.Search(parameters);

Console.WriteLine(paginatedTweets);

Project policies

Read Contributing, Governance, and Security.

See OpenSSF evidence for verified controls and remaining blockers.

Semantic versioning

The package follows SemVer. Before v1.0, minor releases may change undocumented internals or behavior unlikely to affect most users.

Review release notes before upgrading between minor versions.

Open an issue for questions, bugs, or suggestions.

Xquik is an independent third-party service. Not affiliated with X Corp. "Twitter" and "X" are trademarks of X Corp.