Note
This project is not affiliated with Aptabase or Sumbit Labs Ltd.
aptabase-rs is a framework-independent Rust SDK for Aptabase, an Open Source, Privacy-First, and Simple Analytics for Mobile, Desktop, and Web Apps.
Install the SDK by adding the following to your Cargo.toml file:
Cargo.toml
[dependencies]
aptabase-rs = "0.1.0"
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }First, you need to get your App Key from Aptabase, you can find it in the Instructions menu on the left side menu.
Then create the client with your app key and application version:
src/main.rs
use aptabase_rs::Builder;
let client = Builder::new(
"<YOUR_APP_KEY>", // 👈 this is where you enter your App Key
env!("CARGO_PKG_VERSION"),
)
.build();You can then start sending events from Rust by calling the track_event method on client.
As an example, you can add app_started and app_exited events like this:
use aptabase_rs::Builder;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = Builder::new("<YOUR_APP_KEY>", env!("CARGO_PKG_VERSION")).build();
client.track_event("app_started", None);
// do some work here...
client.track_event("app_exited", None);
client.flush().await;
Ok(())
}A few important notes:
- The SDK will automatically enhance the event with some useful information, like the OS, the app version, and other things.
- You're in control of what gets sent to Aptabase. This SDK does not automatically track any events, you need to call
track_eventmanually.- Because of this, it's generally recommended to at least track an event at startup.
- You do not need to await for the
track_eventfunction, it'll run in the background. - Only strings and numbers values are allowed on custom properties.
It's possible to load the APTABASE_KEY from a .env file at compile time using the dotenvy_macro crate. The .env file needs to be
in the project directory for the dotevny_macro crate to find it properly.
Add the use declaration to where you are building the SDK (likely main.rs), and then call it where you would put the key.
use aptabase_rs::Builder;
use dotenvy_macro::dotenv;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = Builder::new(dotenv!("APTABASE_KEY"), env!("CARGO_PKG_VERSION")).build();
client.track_event("app_started", None);
// do some work here...
client.track_event("app_exited", None);
client.flush().await;
Ok(())
}By default, the SDK generates an in-memory session ID which rotates every 4 hours or whenever the app restarts. Applications which start and exit frequently may want to persist the session ID to disk so it can be reused across restarts.
To implement persistent sessions, generate a new session ID with aptabase_rs::new_session_id() and persist it to your application's storage (file, database, etc.). This can be loaded at startup and passed to the builder with Builder::with_session_id(). When you do this, your application is responsible for rotating the persisted session ID; if it keeps reusing the same stored ID, those runs will be grouped into the same session.
use aptabase_rs::Builder;
use std::fs;
let session_path = "aptabase-session-id";
let session_id = fs::read_to_string(session_path).unwrap_or_else(|_| {
let id = aptabase_rs::new_session_id();
fs::write(session_path, &id).expect("failed to persist Aptabase session ID");
id
});
let client = Builder::new("<YOUR_APP_KEY>", env!("CARGO_PKG_VERSION"))
.with_session_id(session_id)
.build();Calling track_event only enqueues events to be sent to the server, you need to explicitly await flush to actually send the queued events. For short-lived applications, this would typically be done at the end of the application's lifecycle.
Long-running applications can opt in to periodic flushing with with_polling(true). The interval defaults to 60 seconds in release builds and 2 seconds in debug builds. This can be customized with with_options(InitOptions). It is important that you still flush manually before the applcation exits, so that any remaining events in the queue are sent to the server.
use aptabase_rs::{Builder, InitOptions};
use std::error::Error;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = Builder::new("<YOUR_APP_KEY>", env!("CARGO_PKG_VERSION"))
.with_polling(true)
.with_options(InitOptions {
flush_interval: Some(Duration::from_secs(30)),
host: None,
})
.build();
// do some long-running work here...
client.flush().await;
Ok(())
}You can use the default panic hook to enqueue a panic event before the process continues to the default panic handler. If the panicking thread has an active Tokio runtime, the hook makes a best-effort delivery attempt with the same Tokio-backed transport. Without an active Tokio runtime on that thread, the panic event is only enqueued in memory before the previous panic hook runs.
use aptabase_rs::Builder;
let client = Builder::new("<YOUR_APP_KEY>", env!("CARGO_PKG_VERSION"))
.with_default_panic_hook()
.build();For custom panic event payloads, provide your own hook:
use aptabase_rs::Builder;
use serde_json::json;
let client = Builder::new("<YOUR_APP_KEY>", env!("CARGO_PKG_VERSION"))
.with_panic_hook(Box::new(|client, info, message| {
let location = info
.location()
.map(|loc| format!("{}:{}:{}", loc.file(), loc.line(), loc.column()))
.unwrap_or_default();
let _ = client.track_event(
"panic",
Some(json!({ "info": format!("{} ({})", message, location) })),
);
}))
.build();- Requests contain at most 25 events and use Aptabase's
/api/v0/eventsendpoint. - Transport failures and HTTP 5xx responses are requeued in memory for a later flush.
- Other unsuccessful HTTP responses are discarded.
- This crate provides only the asynchronous Tokio transport; it does not expose a blocking flush API.
The client never tracks events automatically. Applications decide which event names and properties to send. Each event includes the app version, SDK version, debug status, OS name and version, and locale. Avoid sending personal or sensitive data in event names or properties.
See Aptabase for service documentation and privacy guidance.