Beacon .NET SDK

The Beacon .NET SDK provides native integration for desktop (WPF, WinForms, MAUI), server (ASP.NET Core, Windows Services), and console applications.

Installation

Install via NuGet:

dotnet add package SoftAgility.Beacon

Or via the Package Manager Console:

Install-Package SoftAgility.Beacon

System Requirements

  • .NET 8.0 or later
  • Windows, Linux, or macOS
  • No additional dependencies

Configuration

ASP.NET Core / Host Builder

Register Beacon with dependency injection to resolve IBeaconTracker:

services.AddBeacon(options =>
{
    options.ApiKey = "your-api-key";
    options.ApiBaseUrl = "https://api.beacon.softagility.com";
    options.AppName = "MyApp";
    options.AppVersion = "1.2.0";
});

Manual Initialization

For applications without dependency injection, use the static Configure method. It returns void and creates a singleton BeaconTracker. Retrieve the instance via BeaconTracker.Instance after configuration:

BeaconTracker.Configure(options =>
{
    options.ApiKey = "your-api-key";
    options.ApiBaseUrl = "https://api.beacon.softagility.com";
    options.AppName = "MyApp";
    options.AppVersion = "1.2.0";
});
 
var tracker = BeaconTracker.Instance!;

Calling Configure a second time throws InvalidOperationException. If required options (ApiKey, ApiBaseUrl, AppName) are missing, the SDK disables itself silently and logs a warning — it does not throw.

Configuration Options

OptionTypeDefaultDescription
ApiKeystringYour Beacon API key (required)
ApiBaseUrlstringBeacon API base URL (required)
AppNamestringThe application name sent as source_app on every event. Must match a product slug registered in the Beacon dashboard, or events are rejected with UNRECOGNIZED_PRODUCT. The SDK truncates values longer than 128 chars before sending. (required)
AppVersionstringYour application’s version string, sent as source_version. The SDK truncates values longer than 256 chars; note the backend rejects source_version values longer than 128 chars, so practically keep this under 128. (required)
EnabledbooltrueEnable or disable tracking globally
FlushIntervalSecondsint60How often to send batched events (1-3600)
MaxBatchSizeint25Events per batch. Values above 1000 are clamped to 1000; otherwise the configured value is used.
MaxQueueSizeMbint10Maximum offline queue size in MB (1-1000)
MaxBreadcrumbsint25Breadcrumb ring buffer size (0-200)
EventsEventDefinitionBuilderBuilder for registering known events
LoggerMicrosoft.Extensions.Logging.ILogger?nullOptional logger for SDK diagnostics

Known limit mismatch (SDK ≤ 1.0.1): The .NET SDK currently truncates AppName at 128 chars and AppVersion at 256 chars. The wire format actually allows the opposite — source_app up to 256 and source_version up to 128. To stay safe today, keep AppName ≤ 128 and AppVersion ≤ 128. A future SDK release will reconcile this with the wire format.

Identifying Users

Before tracking events or sessions, identify the current actor (user or device):

tracker.Identify("user-123");

Actor IDs can be up to 512 characters. Once identified, all subsequent Track, StartSession, and TrackException calls use this actor. You can also pass an explicit actor ID to any tracking method.

Tracking Events

Events are organized by category and name, with optional properties.

Basic Event

tracker.Track("ui", "button_clicked", new
{
    button_name = "export",
    screen = "dashboard"
});

With Explicit Actor

tracker.Track("reports", "report_exported", "user-456", new
{
    format = "pdf",
    row_count = 1500
});

Event Limits

  • Category: max 128 characters
  • Name: max 256 characters
  • Actor ID: max 512 characters

Session Management

Sessions group related events and track duration.

// Start a session (uses the identified actor)
tracker.StartSession();
 
// Or start with an explicit actor ID
tracker.StartSession("user-123");
 
// End the current session
tracker.EndSession();

Exception Tracking

Track handled or unhandled exceptions with full stack traces. The SDK sends the exception type, message, and stack trace to the Beacon API, which assigns a fingerprint and groups similar exceptions together.

try
{
    ProcessOrder(order);
}
catch (Exception ex)
{
    tracker.TrackException(ex, ExceptionSeverity.NonFatal);
    throw;
}

Severity options are ExceptionSeverity.Fatal and ExceptionSeverity.NonFatal. Recent tracking calls are automatically attached as breadcrumbs to provide context.

The SDK maintains a circular ring buffer of recent Track calls. When an exception is reported, these breadcrumbs are attached automatically, giving you a timeline of what happened before the error.

Configure the buffer size with MaxBreadcrumbs (default 25, max 200). Set to 0 to disable.

Flushing Events

Events are batched and sent on a timer (FlushIntervalSeconds) or when the batch reaches MaxBatchSize. To flush manually:

await tracker.FlushAsync();

Check the last flush result:

FlushStatus status = tracker.LastFlushStatus;

Offline Persistence

The SDK queues events in a local SQLite database under the OS-specific Local Application Data directory (e.g., %LOCALAPPDATA%\SoftAgility\Beacon\{SanitizedAppName}\queue.db on Windows; equivalent paths on Linux and macOS). The application name is sanitized for safe filesystem use. Events persist across application restarts and sync automatically when connectivity returns.

  • FIFO queue with a configurable maximum size (MaxQueueSizeMb)
  • Best-effort durable retry: events are retained on disk through transient network failures, but if the queue reaches the configured size cap, the oldest events are evicted to make room for new ones
  • Background timer handles automatic flushing
  • Permanent failures (4xx errors other than 401/402/429) are not retried; events are dropped with a logged warning

To guarantee delivery before shutdown, call await tracker.FlushAsync() explicitly. Disposing the tracker persists in-memory events to disk for the next launch but does not perform a network flush.

Event Manifest

Export a JSON manifest of your registered events for import into the Beacon portal’s allowlist page:

tracker.ExportEventManifest("events.json");

Thread Safety

BeaconTracker is fully thread-safe. A single instance can be shared across your application and called from any thread.

Disposal

BeaconTracker implements both IDisposable and IAsyncDisposable. Dispose when your application shuts down to release resources and persist in-memory events to disk for the next launch:

// To deliver pending events to the network before shutdown:
await tracker.FlushAsync();
 
// Then release resources:
tracker.Dispose();
// or
await tracker.DisposeAsync();

Disposal alone does not perform a network flush — pending events are written to disk and sent on the next session. For immediate delivery at shutdown, call FlushAsync first.

WPF Example

public partial class App : Application
{
    private IBeaconTracker _tracker;
 
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
 
        BeaconTracker.Configure(options =>
        {
            options.ApiKey = "your-api-key";
            options.ApiBaseUrl = "https://api.beacon.softagility.com";
            options.AppName = "MyDesktopApp";
            options.AppVersion = "2.1.0";
        });
        _tracker = BeaconTracker.Instance!;
 
        _tracker.Identify("device-" + Environment.MachineName);
        _tracker.StartSession();
    }
 
    protected override async void OnExit(ExitEventArgs e)
    {
        _tracker.EndSession();
        await _tracker.FlushAsync();
        _tracker.Dispose();
        base.OnExit(e);
    }
}

Next Steps