Skip to content
Console
Browse documentation
Guide

Choose a mobile SDK

Connect iOS, Android, React Native, or Flutter activity to the same customer story.

On this page

Anectico's mobile SDKs share the same identity, session, event, error, crash, retry, and propagation contract. Choose the SDK that owns your application's runtime:

Application Guide Minimum or key requirement
Native Apple iOS iOS 15+, Swift Package Manager
Native Android Android minSdk 24, Kotlin and Gradle
React Native React Native React Native 0.73+, native build setup
Flutter Flutter Flutter plugin with native Android and iOS SDKs

During early access, some registry packages may not be published. Use the source coordinate or package artifact shown in the platform onboarding instructions.

Shared behavior

Configure the SDK once at application startup, identify after login, and call reset at logout. A stable distinct_id connects product events, caught errors, native crashes, and backend requests to one customer. Use an id from your own system: an email address sent as a property is stored as [REDACTED] (see What Anectico redacts and withholds). On Android, iOS, and their React Native bridges, reset also clears global error-user context and buffered breadcrumbs so prior-account diagnostics cannot cross a shared-device logout boundary.

Use separate project-bound credentials: apiKey is a native_ingest key with ingest:write; captureApiKey is a mobile_capture key with analytics:write. See native intake keys. Never include server, read, management or agent credentials in an application build. Without a capture key, product and identity collection is disabled locally while OTLP remains available. Supplied malformed or shared capture keys reject configuration. Mobile capture is public-client provenance, not trusted server authority.

Each SDK persists diagnostic events before batching and retries failed delivery with stable message IDs. Fatal native crashes are spooled and sent on the next launch. Optional structural replay has independent controls; source coverage and device qualification remain separate.

Native Android additionally exposes durable Anectico.captureLog OTLP logs. It snapshots occurrence time and customer, session, app and device context before an atomic sandbox write and retries across process recreation. iOS, React Native, and Flutter do not yet expose the same public log API.

Remote flags and headless surveys

Bounded remote flags and application-rendered surveys are available in the canonical Swift source and Kotlin source. React Native and Flutter delivery use typed native bridges. All four SDKs expose these optional APIs.

Alongside core tests, an isolated Android API 36 x86_64 emulator run has built and installed standard Android, React Native and Flutter apps. Their flag exposures and survey answers join one person while preserving each original session. This covers the tested Android emulator configuration; Apple runtimes, physical devices and published-package installation require separate verification.

Start with the guide for your runtime:

Your application renders the survey and reports actual display, response or dismissal. Test the linked runtime, delivery and stored person and session evidence independently. Native replay has its own setup below.

Hosts and four credentials

Both native SDKs use applicationEndpoint, projectID, flagDeliveryApiKey, surveyDeliveryApiKey and surveyScreenPaths. applicationEndpoint is the application HTTPS host for /api/v1/flags/evaluate and survey delivery. Ingestion endpoint is a different base for OTLP and /api/v1/capture; never assume the two hosts are interchangeable.

Option Project-bound purpose Exact scope
apiKey native_ingest ingest:write
captureApiKey mobile_capture analytics:write
flagDeliveryApiKey CLIENT_DELIVERY flags:evaluate
surveyDeliveryApiKey CLIENT_DELIVERY surveys:respond

Issue two delivery keys by default using the existing preview and confirmation flow. CLI purpose is client_delivery. Keep a stable idempotency key and fixed expiry per proposal; the secret is shown once. Agent and operator credentials stay outside application builds. Never embed flags:read, MCP scopes or a server APPLICATION key with experiments:deliver, and never widen intake permissions. A delivery key cannot send exposure events.

Use the private HTTPS hosts supplied by your operator and the approved private network path on every testing device. Configure both endpoints explicitly; a successful core test does not prove the device can reach either. Do not expose a private API publicly to make setup work.

Current identity and targeting

Use the same stable signed-in ID in the same project on web and mobile. Each device has its own anonymous ID and session. Changed exact identity clears groups; identifying the same exact ID preserves them. Identify updates local state only after admission and joins aliases asynchronously. Rejected admission leaves the old identity; an admitted reset rotates identity and session. Read aliases and the timeline before claiming that devices joined. A canonical person joins evidence; flag hashing still uses the request's distinct ID. Equal variants require the same current identity and targeting context, not merely aliases of one person.

With disabled analytics or no capture key, evaluation requires an explicit current binding: Swift setEvaluationBinding(FlagEvaluationBinding(distinctID:personProperties:groups:)), Kotlin setEvaluationBinding(distinctId, personProperties, groups). Without one the outcome is identity_unavailable and no request is sent. Binding replacement and clearing invalidate old decisions independently of telemetry identity and session. Withdrawal retires implicit work; renewed consent does not apply an earlier refused identify or reset. An explicit decision for B cannot emit an exposure attributed to frozen telemetry subject A.

Request properties are declarations. Client keys cannot read stored person or group properties, cohort membership or event content; withheld sources stay withheld. Protected targeting requires your own authenticated backend with the needed authority, never broader embedded permissions.

Evaluate selected keys and inspect states

Your agent uses its own flags:evaluate credential and mcp:read for the read gateway:

anectico flags evaluate user_8842 --key enabled --key disabled --key checkout_variant \
  --key missing --key dependency_error --person-properties '{"plan":"pro"}' \
  --groups '{"company":"acme"}' --project PROJECT --json

MCP: execute_read_action with action evaluate_client_flags, exact project_id, distinct_id, flag_keys, person_properties and groups. Repeat --key; each context flag takes one JSON object. Independently configure the test definitions before expecting these example results:

Selected key Expected state and value
enabled evaluated, boolean true
disabled evaluated, boolean false
checkout_variant evaluated, string treatment
missing unavailable_flag, no value
dependency_error evaluation_error, server default marked is_fallback, no version

A name alone does not create a fixture or cause an error. All absent or false results prove no positive parity. Native boolean reads require an explicit application fallback and retain its use and the original reason. Decisions expire at original evaluated_at plus 30 seconds and remain only in memory. Bootstrap must match the original project, current identity, context, keys and generation; installing it cannot renew its lifetime. Reload selects 1–100 unique keys, at most ten groups and 16 KiB of targeting context. No all-flags or local-definition client mode exists.

Exposures are separate evidence

Served value and payload reads may admit $feature_flag_called when product consent, a mobile_capture key and the matching telemetry context permit it. Status inspection emits nothing. Preserve the evaluated definition's exact definitionVersion string from reload, cache and bootstrap through exposure $feature_flag_version; do not round its six fractional digits or substitute decision_context_id. Unavailable, fallback and unversioned decisions invent no version.

Exposure metadata includes $feature_flag, $feature_flag_response, $feature_flag_evaluation_status, $feature_flag_is_fallback, $feature_flag_evaluation, $feature_flag_input_context and optional $feature_flag_test_case_id. Deduplication includes identity, key, value and exact version: equal values at different versions must yield separate exposures. Immutable retries retain the original message ID, identity, session, time and metadata.

Verify the original application's message_id, source_id, distinct ID and session using anectico doctor events --file verify.json (verify_integration_events through the read gateway) and the flag verifier. Read version and input context agreement independently; unversioned evidence is not_comparable. A current decision, cache freshness or aggregate flush does not prove that exposure was served or stored. The current native flag APIs expose no public per-exposure receipt, so exact attribution of a particular native attempt remains unqualified. An ID found only after storage cannot fill that gap. Flag evaluation has no proof link.

Headless display, delivery and storage

Map explicit screen names with surveyScreenPaths, for example Checkout to /checkout or /mobile/checkout; never include raw URLs or route arguments. Your app renders questions, records shown only after actual display, and submits or dismisses only on the user's action. The native guides show single choice, multiple choice, integer rating including zero, and open text. The server owns audience and flag targeting, sampling, caps and cooldown. Refresh coalesces with a five-second floor and no unconditional foreground polling. At most three offers describe one screen, identity and time. A valid empty list differs from a transport error or SURVEY_IDENTITY_COVERAGE_UNSUPPORTED; permanent delivery refusal closes the handle.

Keep the original delivery ID, offered revision, answers, identity and optional source session immutable through uncertain retries on the same handle. Do not generate a new ID or change answers to retry. Identity or context changes, screen replacement, withdrawal, shutdown and reconfiguration retire incompatible handles and clear answer memory. There is no new persisted answer spool and the SDK emits no duplicate survey outcome events.

The clients freeze source sessions and recognize the coverage refusal. Source-session propagation and complete-alias refusal are implemented; independently verify stored correlation on the deployment and runtime you use. Earlier browser or REST survey results do not qualify the client-delivery authority change. Always provision the literal client-delivery purpose.

An accepted receipt precedes event visibility. Read retained delivery evidence, stored answers and the joined person timeline separately. Multiple selected options create multiple response event rows; those rows are not response totals. Agent definitions need surveys:read; mutations additionally need surveys:write, mcp:write and server preview and confirmation. Results and answers need analytics:read, analytics:query, persons:read, agents:content:read and mcp:read over MCP. SDK delivery has only surveys:respond; there is no agent visitor-submission command.

Privacy and qualification limits

Answers and exposure events remain subject to content permissions and current policy, event retention, person erasure and export and project or workspace deletion. Local withdrawal clears pending memory and prevents new collection; it does not erase previously stored data. Evidence lifetime follows its source: a platform-held result or receipt cannot preserve erased or expired answers. Chat copies or downloaded exports already delivered outside the platform cannot be recalled. Unavailable, withheld, erased and not observed are separate states. Use existing person and result proof links where returned. Native replay is a separate capability and is not qualified here.

Mobile parity is declared and unqualified. Record each SDK, operating system, runtime, source revision, package installation, copied-source equality and required stored readback independently as pass, fail, skip or blocked. Core tests, source presence, package coordinates and a flush do not establish runtime support or installability. No prices or plan allowances are implied.

Native structural replay

Optional recorders and adapters use native_structural version 1 (NR1). Each requires independent replay consent, an explicit current owner, current native capture policy and native store permission, and a separate project-bound replay_upload key with only replay:write.

Runtime Setup and source coverage
iOS Explicit UIKit source; unqualified SwiftUI and embedded regions remain gaps.
Android Android View recorder; Compose, custom and embedded regions remain gaps.
React Native Host refs and component privacy; inspect the source matrix for the hosts you use.
Flutter Dart structural adapter; native view traversal cannot observe Dart UI.

Replay does not start with analytics consent or a flag identity. Follow recording and verification and native recording privacy. An upload receipt alone does not establish retained playback, complete source coverage or physical-device qualification.

Check plan allowances

Read the current plan allowances and limits before a rollout. Your agent's budgets and spend controls are separate from SDK delivery outcomes. Recorder safety ceilings are not sustainable device rates or included allowances.

Record an explicit agent run

All four mobile SDKs provide startAgentRun to record a source-declared invoke_agent span. Start it when your app's agent begins work and end it once with the real terminal outcome; do not use it as a generic checkout or network span. Options, status enums, validation, and return values vary by language:

Releases and readable stacks

Set a stable release and optional dist for every production build. Upload the matching artifacts:

  • iOS: dSYM;
  • Android: R8 or ProGuard mapping.txt;
  • React Native: native artifacts plus Metro source maps; and
  • Flutter: native artifacts. Obfuscated Dart frames are not currently symbolicated by Anectico.

Release and distribution values must match the captured error exactly. The same release value also stamps the reserved $release/$app_version string properties on every captured event, not only on errors — see each SDK's own guide and Reserved event properties.

Connect a mobile request to the backend

Use the SDK's propagation helper to add W3C traceparent and baggage to calls sent to a trusted, instrumented backend. Do not attach identity baggage to arbitrary third-party requests. The backend must treat customer identity headers from public devices as untrusted and verify or replace them at its gateway.

Verify

Launch a release build, identify a test customer, capture one event and one caught error, and make one request to an instrumented backend. Ask your agent to read that customer's timeline (get_person_timeline over MCP, or anectico persons timeline <customer-id>) and confirm the mobile and backend evidence is connected under the same ID. The MCP result carries a link that opens the customer as a read-only proof page. Then ask your agent for the issue (get_issue, or anectico issues view <issue-id>) and verify its stack is readable after uploading symbols.