Skip to main content
This page describes core configuration, RUM configuration, privacy controls, Trace correlation, crash reporting, and symbol upload for the HarmonyOS SDK. All options come from the current ArkTS SDK public API.

Core configuration

Create core configuration with ConfigurationBuilder and pass it to Flashcat.initialize().
These three settings share their names and values with the Android, iOS and Flutter SDKs, so tuning advice transfers between platforms unchanged.Since SDK 0.5.0, setBatchUploadFrequencyMs(5000) is replaced by setUploadFrequency(UploadFrequency.RARE). Two defaults changed at the same time, both to match the other platforms: the upload interval went from 5 s to 2 s, and the batch window from 5 s to 10 s.
Flashcat.initialize() initializes a given instance name only once. A duplicate call returns the existing instance and does not re-register feature modules.

Reducing the impact of uploads on your own requests

If the app makes latency-sensitive requests of its own (sign-in, checkout, key provisioning) over a narrow uplink, SDK uploads can compete with them for the uplink. The symptom is a higher tail (P95) on your own request latency that comes and goes. Lower all three settings together to change how uploads are distributed over time — fewer uploads, spread further apart:
These three settings only change when uploads happen. They drop no events and remove no dimension from your dashboards, so if you do not want to sacrifice data, tune only these. BatchSize.LARGE has an extra benefit: larger batches compress better, so uplink bytes drop slightly.
Tuning advice transfers between platforms unchanged, because these three settings share names and values with the Android, iOS and Flutter SDKs. The one difference is that iOS batchProcessingLevel = .low is 5 batches per cycle, while HarmonyOS and Android use 1 — same direction, smaller reduction. See Android SDK performance impact and iOS SDK performance impact.
Several things that need to be turned off on other platforms cost nothing on HarmonyOS, and are neither configurable nor necessary: If the event volume itself is high, use event mapping with setEventMapper to drop specific noisy events (return null to drop). That is less invasive than changing your instrumentation. To comply with privacy regulations such as GDPR and CCPA, the SDK requires a tracking consent state at initialization (the third argument of Flashcat.initialize()), and lets you change it at any time afterwards.
When initialized with TrackingConsent.PENDING, the SDK writes events to a separate local buffer and sends nothing until consent changes to GRANTED — at which point the buffered data is migrated and uploaded automatically. Changing to NOT_GRANTED clears the buffer instead.
Every launch uses the value you pass to Flashcat.initialize. The SDK never overrides it with a previously stored state — the same contract as the Android and iOS SDKs. Your application is responsible for storing the user’s choice and passing it back at every initialization.
If your application initializes the SDK with a hard-coded value (for example GRANTED) on every launch, collection resumes after a restart even for a user who revoked consent. Call setTrackingConsent at the moment the user makes a choice, persist that choice yourself, and pass it to initialize on the next launch.
The consent state is also persisted locally, but it serves exactly one purpose: the WorkSchedulerExtensionAbility used for background upload runs in a separate process with no user in front of it and no access to the application’s decision, so it reads the main process’s last recorded state. See Background and deferred upload. When consent is revoked (changed to NOT_GRANTED), the SDK clears the unsent pre-consent buffer and deletes batches already written to disk but not yet uploaded. On 0.2.0 and earlier only the buffer was cleared, so collected batches were still sent once consent came back. Starting in 0.3.2, revoking consent also deletes the local view snapshot used for crash attribution. That snapshot is a whole view event — user id, name, email, and any custom context — so it is just as personal as a collected batch. At initialization:
After initialization, via the setTrackingConsent API (for example once the user responds to your privacy dialog):
Trace headers also honor tracking consent. The SDK injects correlatable traceparent and tracestate headers only when consent is GRANTED.

RUM configuration

Create RUM configuration with RumConfigurationBuilder and pass it to FlashcatRum.enable().
setTrackErrors(false) disables automatic error capture only. Crash reporting is unaffected: with the crash module enabled, uncaught exceptions still follow JsCrashPolicy — they are persisted, counted, and replayed as is_crash errors into the session that crashed. Manual addError calls are the application’s explicit intent and are also still delivered. Use setEventMapper() if you need to filter those too.

Event mapping and redaction

Use setEventMapper() to perform lightweight processing before events are reported. Return the modified event to keep it, or null to drop it.
The event mapper runs on the SDK write path. Keep it fast, synchronous, and non-throwing. The SDK catches mapper errors and preserves the original event, but expensive logic increases client overhead.

Global attributes and user information

Global attributes are merged into the context object on subsequent events.
On sign-out, call clearAttributes() to drop the previous user’s business attributes and then stopSession(), so two users’ behavior never lands in the same session.
Set user information through the core instance. id, name, and email are written to the usr object on subsequent events.
setUserInfo() currently sets only id, name, and email. The server does not accept other user fields; use RUM global attributes or per-event attributes to write business dimensions to context.

Trace configuration

The Trace module generates W3C traceparent and tracestate, then correlates the generated trace id and span id to RUM resources through _dd.trace_id and _dd.span_id. tracestate carries the Datadog vendor entry dd=s:{0|1};o:rum.
setFirstPartyHosts() is currently used only by the FlashcatHttp wrapper. The rcp interceptor itself is an explicit per-session opt-in, so requests made through a session with the interceptor receive Trace headers. If a request already has traceparent, the SDK does not overwrite the existing Trace context. Existing tracestate keeps other vendors and moves the updated dd= member to the front.

Crash reporting configuration

The Crash module provides two collection paths:
  • It listens to HarmonyOS hiAppEvent for APP_CRASH and APP_FREEZE, then reports system-replayed fault events through the RUM error pipeline on a later launch
  • It handles uncaught main-thread ArkTS exceptions live and uses JsCrashPolicy to report before the process exits or restarts
The default JS crash policy is REPORT_THEN_EXIT.
Starting in 0.2.0, the default changes from the legacy keep-alive behavior to REPORT_THEN_EXIT. Merely initializing an earlier SDK suppressed host application exit after an uncaught ArkTS exception, leaving the application running with undefined business state. The new default synchronously persists the crash and restores platform exit semantics. To restore the old behavior, explicitly set JsCrashPolicy.OBSERVE_ONLY and confirm that retaining a damaged process matches your business requirements.

REPORT_THEN_EXIT

This is the default policy. When an uncaught synchronous or asynchronous main-thread ArkTS exception occurs, the SDK synchronously persists a crash incident, flushes the current RUM writers, and exits the process. The incident is replayed into RUM on the next launch. If the synchronous write fails, the SDK attempts an asynchronous report and still exits.

REPORT_AND_RECOVER

The SDK synchronously persists the crash incident, checks the persisted crash-loop guard, then calls appRecovery.saveAppState() and restartApp(). The old process exits and a new process starts. The incident replayed on the next launch includes crash.recovered: true. If recovery cannot be enabled, loop history cannot be persisted, the guard trips, the incident cannot be marked as recoverable, or the restart request fails, the SDK degrades to exit behavior.

OBSERVE_ONLY

The SDK reports the exception asynchronously and leaves the current process running. This policy restores the pre-0.2.0 keep-alive behavior and does not exit or restart the process. The event loop may remain responsive, but the uncaught exception may have left the application in a broken or inconsistent business state.

Crash-loop protection

Crash-loop protection affects only REPORT_AND_RECOVER. With the defaults, the first two crashes in a 60-second rolling window can restart the application. The third crash is reported synchronously but degrades to exit: the Nth crash in the window is blocked from restarting, allowing at most N-1 recovery restarts. Crash timestamps persist across processes, so restarting the application does not reset the guard. After the guard trips, each blocked crash becomes the newest timestamp. The application must remain crash-free for the full five-minute cooldown before history resets. Setting setCrashLoopThreshold(1) disables recovery restarts entirely: every crash is still reported synchronously, but each one exits and is never marked with crash.recovered.

Restore host application state

Automatic restart does not define which page state to restore. The host UIAbility must implement onSaveState, copy the required state into wantParam, and return ALL_AGREE:
The host application must read these parameters from the recovery Want and restore only state that is safe to resume. State restoration requires the host to implement onSaveState; the SDK triggers the state save and the restart when a crash occurs.

Capability boundary

Enable RUM and Crash early after Flashcat.initialize(). JS crash policy delivery does not depend on enable order: Crash pushes the policy to RUM, and RUM also pulls it on start, so enabling either module first activates the policy. Enabling FlashcatRum.enable() before FlashcatCrash.enable() is still recommended so pending crash incidents from the previous launch replay immediately. Crash events require the RUM pipeline for publication.

Background and deferred upload

By default, the SDK uploads on the foreground cadence configured by setUploadFrequency() and triggers flush() when the application backgrounds. If you want HarmonyOS WorkScheduler to wake the app for uploads, register deferred upload work.
The SDK registers the WorkScheduler task. The task is persisted (isPersisted, surviving reboots) and repeats on a 2-hour cycle.

Initializing inside the extension process

A WorkSchedulerExtensionAbility runs in a separate process and does not share the main process’s SDK instance. When it wakes, initialize with initializeForDeferredUpload before calling flushAndWait():
MyUploadExtensionAbility.ets
initializeForDeferredUpload differs from initialize in two important ways:
  • It takes no consent argument. The extension has no user in front of it, so it acts only on the main process’s last persisted decision. If nothing is persisted (the main application never initialized) or the stored decision is NOT_GRANTED, it reads, migrates, and uploads nothing.
  • It is read-only. It never writes back consent, device identity, or work registrations. HarmonyOS Preferences are per-process whole-file caches, so a write from the extension could clobber a revocation happening concurrently in the main process.
Do not call Flashcat.initialize() inside the extension process. It would overwrite the persisted consent state with the literal you pass, which can resume uploads after the user revoked consent. setTrackingConsent is also ignored in the extension process and logs an error.

Upload HarmonyOS crash symbols

To de-obfuscate ArkTS stacks and symbolicate native .so stacks in the console, upload build artifacts with @flashcatcloud/hvigor-plugin. The plugin uploads two artifact types: The plugin ships as an npm package (on npm, not ohpm); install it as a build-time dev dependency in your project’s root package.json, not in oh-package.json5:
Then register the plugin in the module’s hvigorfile.ts:
hvigorfile.ts
On SaaS, omit endpointhvigor-plugin ≥ 0.1.3 defaults to https://ci.flashcat.cloud (not the RUM ingest host browser.flashcat.cloud). For a private deployment set FLASHCAT_SOURCEMAP_INTAKE_URL (scheme + host, no path; also requires ≥ 0.1.3), or pass endpoint: 'https://rum.example.com'. Plugin 0.1.2 does not honour FLASHCAT_SOURCEMAP_INTAKE_URL — set endpoint explicitly, or use the legacy FLASHCAT_ENDPOINT env var (deprecated in 0.1.3 but still honoured). flashcatSymbolUploadPlugin() also accepts two optional fields: buildDir (build output directory, default build/default) and pluginVersion (the version sent in the DD-EVP-ORIGIN-VERSION upload header, which defaults to the plugin’s own version). Neither is normally required.
Run the upload task after a release build:
The plugin sends multipart/form-data to {endpoint}/sourcemap/upload: Upload event types:
Native symbolication depends on the GNU build-id in each .so. The HarmonyOS NDK generates build-id by default. If your build pipeline disables it, add -Wl,--build-id for the .so.