Beacon C++ SDK
The Beacon C++ SDK provides native integration for Windows desktop applications, server processes, and cross-platform C++ projects.
Installation
CMake FetchContent (recommended)
Add Beacon to your CMakeLists.txt:
include(FetchContent)
FetchContent_Declare(
beacon_sdk
GIT_REPOSITORY https://github.com/softagility/beacon-sdk-cpp.git
GIT_TAG v3.0.0
)
FetchContent_MakeAvailable(beacon_sdk)
target_link_libraries(your_app PRIVATE beacon_sdk)Build from Source
git clone https://github.com/softagility/beacon-sdk-cpp.git
cd beacon-sdk-cpp
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config ReleaseDependencies (libcurl, nlohmann_json, SQLite3) are fetched automatically via CMake FetchContent if not found on the system.
vcpkg
A vcpkg port is planned for a future release. For now, use CMake FetchContent or build from source.
System Requirements
- C++17 or later
- Windows 10+, Linux (glibc 2.28+), or macOS 12+
- CMake 3.25+
- libcurl, nlohmann_json, SQLite3 — resolved automatically by CMake FetchContent if not present
- OpenSSL development headers — required on Linux and macOS via
find_package(OpenSSL). On Windows, TLS uses Schannel and no extra dependency is needed.
The SDK selects the TLS backend based on platform: Schannel on Windows, OpenSSL on Linux and macOS.
v3.0.0 (breaking change): The config fields were renamed —
app_name→product(v2.0.0) andapp_version→product_version(v3.0.0) — and the wire fieldssource_app→productandsource_version→product_version. Upgrading from 1.x: renameopts.app_name→opts.productandopts.app_version→opts.product_version. Values are unchanged. See the CHANGELOG.
Configuration
#include <beacon/beacon.hpp>
int main()
{
auto tracker = beacon::Tracker::configure([](beacon::Options& opts) {
opts.api_key = "your-api-key";
opts.api_base_url = "https://api.beacon.softagility.com";
opts.product = "MyApp";
opts.product_version = "1.2.0";
});
tracker->identify("user-123");
tracker->startSession();
// Your application code here...
tracker->endSession();
return 0;
}You can also pass an Options struct directly:
beacon::Options opts;
opts.api_key = "your-api-key";
opts.api_base_url = "https://api.beacon.softagility.com";
opts.product = "MyApp";
opts.product_version = "1.2.0";
auto tracker = beacon::Tracker::configure(opts);Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
api_key | std::string | — | Your Beacon API key (required) |
api_base_url | std::string | — | Beacon API base URL (required) |
product | std::string | — | Your product’s slug as registered in the Beacon dashboard (e.g., "inventory-manager"). Sent as the product field on every event. Must match exactly or events are rejected with UNRECOGNIZED_PRODUCT. (required) |
product_version | std::string | — | Your application’s version string. (required) |
enabled | bool | true | Enable or disable tracking globally |
flush_interval_seconds | int | 60 | Batch send interval in seconds (1-3600) |
max_batch_size | int | 25 | Events per batch, clamped to 1-1000 |
max_queue_size_mb | int | 10 | Maximum offline queue size in MB (1-1000) |
max_breadcrumbs | int | 25 | Breadcrumb ring buffer size (0-200) |
logger | std::shared_ptr<beacon::ILogger> | nullptr | Optional logger for SDK diagnostics |
events | EventDefinitionBuilder | — | Builder for registering known event categories and names. Optional; populated via tracker->exportEventManifest(). |
Identifying Users
Before tracking events or sessions, identify the current actor:
tracker->identify("user-123");Once identified, all subsequent calls use this actor. You can also pass an explicit actor ID to tracking methods.
To read the currently identified actor:
std::string current = tracker->actorId(); // returns "" before identify() is calledAccount & License Context
setAccount / setLicense (added in 1.1.0) attach a customer-account ID and / or license ID to every subsequent event, session start, and exception report. Use them for B2B analytics when your application services multiple customer organisations.
tracker->identify("user-123");
tracker->setAccount("acct_acme"); // customer organisation
tracker->setLicense("sub_acme_team_annual"); // contract / entitlement
tracker->startSession();
tracker->track("reports", "report_exported", {}); // event carries both IDsBehaviour:
- Persistence. Values are stored in process memory and applied to every subsequent payload until cleared or
reset()is called. - Validation. 1-256 chars after trim, no whitespace-only, no control characters (including U+2028 / U+2029). Invalid input is silently ignored at
Warninglog level and does NOT overwrite a previously valid value. - Clearing.
clearAccount()andclearLicense()each clear only their own field.reset()clears actor, session, account, license, queue, and breadcrumbs. - Opt-out.
setAccount/setLicenseare no-ops while opted out;clearAccount/clearLicenseare always safe to call. - Per-call payload. When set,
account_id/license_idare included as top-level JSON fields. When unset, the fields are omitted entirely.
Modeling licenses
Prefer per-contract license IDs (one ID shared across every user of a subscription / site / bundle):
tracker->setLicense("sub_acme_team_annual"); // recommendedPer-user / per-seat IDs are accepted but make the dashboard’s License Detail page thin. See the Licenses section of the user manual.
Account- and license-level analytics in the Beacon dashboard are gated to Business and Enterprise plans (Trial also during evaluation). Ingestion itself is tier-blind.
Tracking Events
Events are organized by category and name, with optional properties.
Basic Event
Properties are passed as std::unordered_map<std::string, std::string>. The C++ API doesn’t accept braced initializer lists directly — wrap explicitly:
tracker->track("ui", "button_clicked",
std::unordered_map<std::string, std::string>{
{"button_name", "export"},
{"screen", "dashboard"}
});With Explicit Actor
tracker->track("reports", "report_exported", "user-456",
std::unordered_map<std::string, std::string>{
{"format", "pdf"},
{"row_count", "1500"}
});Session Management
// 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 exceptions with severity levels. Breadcrumbs from recent track() calls are attached automatically.
try
{
process_order(order);
}
catch (const std::exception& ex)
{
tracker->trackException(ex, beacon::ExceptionSeverity::NonFatal);
throw;
}Severity options: beacon::ExceptionSeverity::Fatal and beacon::ExceptionSeverity::NonFatal.
Flushing Events
Events are batched and sent on a timer or when the batch size is reached. To flush manually:
bool success = tracker->flush(); // Blocks up to 30 secondsCheck the last flush result:
beacon::FlushStatus status = tracker->last_flush_status();Offline Persistence
Events are persisted to a local SQLite database when the network is unavailable. The queue syncs automatically when connectivity returns.
- Persists across application restarts
- Thread-safe queue with a configurable size limit (
max_queue_size_mb) - Best-effort durable retry: events are retained through transient network failures, but if the queue reaches the configured cap, the oldest events are evicted. Permanent HTTP errors (non-retriable 4xx other than 401/402/429) discard the affected events.
- Call
tracker->flush()at shutdown to deliver pending events before the process exits.
Privacy Controls
The SDK supports opt-out and opt-in for user consent:
tracker->optOut(); // stops tracking, clears queue
tracker->optIn(); // resumes trackingOpt-out state persists across application restarts via the offline-persistence database.
Breaking change in 1.2.0 (unreleased): the methods are renamed from
opt_out()/opt_in()tooptOut()/optIn()to match the camelCase style of every other multi-word public method onTracker(startSession,endSession,setAccount,setLicense,trackException,exportEventManifest). The README has always documented the camelCase form. No compatibility alias is provided — call sites pinning the SDK at 1.2.0 or later must update.
Reset
Clear all in-memory state (session, queue, breadcrumbs, actor ID) and generate a new anonymous device ID:
tracker->reset();Use this on logout to separate user sessions.
Event Manifest
Register known events for import into the Beacon portal’s allowlist:
tracker->exportEventManifest("events.json");Singleton Access
After calling configure(), retrieve the tracker instance anywhere with:
auto tracker = beacon::Tracker::instance();Call beacon::Tracker::reset_for_testing() in test teardown to clear the singleton.
Thread Safety
beacon::Tracker is fully thread-safe. Share a single instance across threads.
Lifetime Management
configure() stores the tracker in an internal static shared_ptr, so a local auto tracker going out of scope does not destroy the tracker — it only releases your local reference. The destructor (when it eventually runs) persists in-memory events to disk and joins worker threads, but does not perform a network flush, end the active session, or send any final HTTP requests.
To shut down cleanly, call endSession() and flush() explicitly before your application exits:
auto tracker = beacon::Tracker::configure(configurator);
tracker->identify("user-123");
tracker->startSession();
// Track events...
// Explicit shutdown
tracker->endSession();
tracker->flush(); // blocks up to 30s waiting for the network round-tripWithout an explicit flush(), in-memory events are persisted to disk and delivered on the next session.
Next Steps
- Getting Started for a general overview
- API Reference for direct HTTP integration
- Verify your first event (User Manual) — confirm ingestion from the Beacon dashboard
- Pricing for plan details