Docs

API reference

Every public class, method, getter, stream, enum and field in lander_flutter 0.2.0.

Everything below is exported by one import:

import 'package:lander_flutter/lander_flutter.dart';
ExportKind
LanderStatic entry point
LanderLinkA link delivered to the app
LanderShortLinkA link created with createLink
LanderConfidenceEnum: how sure Lander is
LanderExceptionError from calls that need the API
landerSdkVersionThe SDK version string

Lander

abstract final class Lander

All members are static. You never create an instance.

Lander.initialize

static Future<void> initialize({
  required String apiKey,
  String baseUrl = 'https://api.golander.link',
  bool enableLogging = false,
})

Starts the SDK. Call it once, as early as possible (before runApp is fine). Loads or creates the install ID, reads the launch link and starts listening for links, then reports the launch with POST /v1/sdk/init in the background. The returned future does not wait for the network.

Prop

Type

  • Throws ArgumentError when apiKey starts with sk_, or does not start with pk_.
  • Never throws for network errors.
  • A second call is ignored and returns the future of the first call.
  • Calls WidgetsFlutterBinding.ensureInitialized().
static Stream<LanderLink> get onDeepLink

A broadcast stream of every link the app receives: Universal Links, App Links, custom scheme URLs and deferred links.

  • Safe to listen to at any time, even before initialize.
  • Links that arrive while nobody listens are buffered and replayed, in order, to the next listener.
  • Includes the launch link unless getInitialLink claimed it first.
  • Unknown links and links that could not be resolved are delivered with isResolved == false and only uri set.
  • Does not include links returned by claimHandoff.
static Future<LanderLink?> getInitialLink()

The link that launched the app, or null. On a first launch this may be a deferred link, so it waits for the launch report in that case. Delivered once: returns null if onDeepLink already delivered it, and after this call onDeepLink will not deliver it.

Throws StateError before initialize.

static Future<LanderShortLink> createLink({
  String path = '/',
  Map<String, Object> params = const {},
  String? title,
  String? campaign,
  String? channel,
  List<String> tags = const [],
  Uri? iosFallbackUrl,
  Uri? androidFallbackUrl,
  Uri? webFallbackUrl,
  String? ogTitle,
  String? ogDescription,
  Uri? ogImageUrl,
  DateTime? expiresAt,
})

Creates a short link with POST /v1/sdk/links. The slug is random and the domain is the project's default domain.

Prop

Type

  • Throws ArgumentError when path does not start with / or a params value is not String, num or bool.
  • Throws LanderException when the request fails after retries.
  • Throws StateError before initialize.

See Creating links.

Lander.claimHandoff

static Future<LanderLink?> claimHandoff(String userId)

Claims the link your backend bound to this user with POST /v1/handoffs, after sign in. Returns the link (isDeferred true, confidence deterministic, method authenticated_handoff) or null when nothing is pending. The newest pending handoff wins and every pending one for the user is cleared.

  • The link is only returned, never also emitted on onDeepLink.
  • Throws ArgumentError when userId, trimmed, is empty or longer than 256 characters.
  • Throws LanderException when the request fails after retries, or with code install_not_registered when the install could not be registered yet.
  • Throws StateError before initialize.

See Deferred links.

Lander.trackEvent

static Future<void> trackEvent(
  String name, {
  Map<String, Object?> properties = const {},
  String? linkId,
})

Records a custom event in the on device queue, which sends it in batches with retries. Completes once the event is queued.

Prop

Type

  • Throws ArgumentError for an invalid name, a linkId that is not a UUID, or properties that cannot be encoded as JSON.
  • Never throws for network errors.
  • Throws StateError before initialize.

See Events.

Lander.installId

static String? get installId

The random UUID v4 of this install, once initialize has completed; null before. Stored outside backups and removed on uninstall.

Test only members

Lander.debugHttpClient, Lander.debugClient and Lander.debugReset() are annotated @visibleForTesting and exist for the SDK's own tests. Do not use them in app code.

@immutable
class LanderLink

A deep link delivered to the app. When Lander knows the link, the fields mirror the ResolvedLink returned by the API. When it does not (unknown link, custom scheme URL, network unavailable) only uri is set and isResolved is false.

Constructors

const LanderLink({
  required Uri uri,
  String? linkId,
  String? url,
  String? path,
  Map<String, Object> params = const {},
  String? campaign,
  String? channel,
  bool isDeferred = false,
  LanderConfidence confidence = LanderConfidence.unattributed,
  String? method,
})

/// A link Lander could not resolve. Only uri is set.
const LanderLink.unresolved(Uri uri)

/// Builds a link from a ResolvedLink JSON object. uri falls back to the link's own url.
factory LanderLink.fromJson(Map<String, Object?> json, {Uri? uri})

The public constructors make it easy to build links in your own tests. See Testing.

Fields

Prop

Type

Getters

Prop

Type

route examples:

uripathroute
https://acme.golander.link/p-123/product/123/product/123
https://acme.golander.link/unknownnull/unknown
acmeshop://product/123?color=rednull/product/123?color=red
acmeshop://null/

Equality and toString

Two LanderLinks are equal when every field is equal (params compared by content). toString() gives a readable summary, for example LanderLink(<id>, path: /product/123, params: {productId: 123}, uri: https://acme.golander.link/p-123, deterministic via universal_link) or LanderLink(unresolved, uri: acmeshop://product/123).

@immutable
class LanderShortLink

A short link created with Lander.createLink.

const LanderShortLink({
  required String id,
  required Uri url,
  required String domain,
  required String slug,
  required String path,
  Map<String, Object> params = const {},
  String? title,
  String? campaign,
  String? channel,
  List<String> tags = const [],
  DateTime? expiresAt,
  DateTime? createdAt,
})

factory LanderShortLink.fromJson(Map<String, Object?> json)

Prop

Type

Two LanderShortLinks are equal when id and url are equal. toString() returns url.toString().

LanderConfidence

enum LanderConfidence { deterministic, probabilistic, unattributed }
ValueMeaning
deterministicMatched by an exact identifier: a Universal Link or App Link open, an Android install referrer token, the iOS Continue in app page or an authenticated handoff.
probabilisticMatched by coarse signals (OS version, country, click time, optionally a network hash) within a short window. Only iOS deferred links of projects that opted in.
unattributedNo link could be tied to this open.
static LanderConfidence parse(Object? value)

Returns the value whose name equals value, or unattributed for anything else.

LanderException

class LanderException implements Exception {
  const LanderException({
    required String code,
    required String message,
    int? statusCode,
    Duration? retryAfter,
  });
}

Thrown by calls that need an answer from the API: createLink and claimHandoff. initialize and trackEvent never throw on network or server errors.

Prop

Type

toString() returns LanderException(code, statusCode): message.

API error codes you may see from the SDK endpoints: validation_error, invalid_domain, destination_blocked (400), invalid_api_key (401), wrong_key_kind, project_suspended (403), install_not_found (404), rate_limited, link_quota_exceeded (429), internal_error (500).

landerSdkVersion

const String landerSdkVersion = '0.2.0';

The version reported to the API as sdkVersion and in the X-Lander-Sdk header.

Network behavior

The SDK only talks to Lander's public API, never to a database.

EndpointCalled byAttempts
POST /v1/sdk/initinitialize, every launch3 on a first launch, 1 otherwise
POST /v1/sdk/resolveEvery http or https link that opens the app2
POST /v1/sdk/eventsThe event queue1 per flush; the queue retries with backoff
POST /v1/sdk/linkscreateLink3
POST /v1/sdk/handoffs/claimclaimHandoff3
  • Every request sends Authorization: Bearer <publishable key>, Content-Type: application/json and X-Lander-Sdk: flutter/0.2.0.
  • Every attempt has a 10 second timeout.
  • Retries happen only for network errors, timeouts, 408, 429 and 5xx, with exponential backoff from 500 ms up to 4 s (or longer if Retry-After asks).
  • Every write carries an Idempotency-Key that stays the same across retries, so a retry never creates a second link, claim or install.

On this page