Docs

Creating links

Make short links from inside the app for share and invite flows with Lander.createLink.

Lander.createLink creates a Lander short link from the app, for example when someone taps Share on a product or Invite a friend. The link works like one made in the dashboard: it opens your app on the right screen, or sends people without the app to the store or your website.

ProductActivity.kt
private fun shareProduct(id: String, name: String) {
    lifecycleScope.launch {
        try {
            val link = Lander.createLink(
                path = "/product/$id",
                params = mapOf("productId" to id),
                title = name,
                channel = "share",
            )
            val send = Intent(Intent.ACTION_SEND)
                .setType("text/plain")
                .putExtra(Intent.EXTRA_TEXT, link.url)
            startActivity(Intent.createChooser(send, "Share"))
        } catch (e: LanderException) {
            Toast.makeText(this@ProductActivity, "Could not create a link: ${e.message}", Toast.LENGTH_SHORT).show()
        }
    }
}

link.url is the shareable URL, for example https://acme.golander.link/x7Kp2Qa. createLink suspends while the request runs, off the main thread, so call it from a coroutine such as lifecycleScope.

When someone opens that link, your app receives a LanderLink with path == "/product/123" and params == mapOf("productId" to "123"). See Receiving links.

From Java

Build a LanderLinkOptions and pass a callback, called on the main thread:

ProductActivity.java
LanderLinkOptions options = new LanderLinkOptions.Builder()
        .path("/product/" + id)
        .param("productId", id)
        .title(name)
        .channel("share")
        .build();

Lander.createLink(options, new LanderCallback<LanderShortLink>() {
    @Override
    public void onSuccess(LanderShortLink link) {
        share(link.getUrl());
    }

    @Override
    public void onError(Exception error) {
        // A LanderException for API and network failures.
    }
});

Kotlin can pass a LanderLinkOptions too: Lander.createLink(options).

Parameters

suspend fun createLink(
    path: String = "/",
    params: Map<String, Any> = emptyMap(),
    title: String? = null,
    campaign: String? = null,
    channel: String? = null,
    tags: List<String> = emptyList(),
    iosFallbackUrl: String? = null,
    androidFallbackUrl: String? = null,
    webFallbackUrl: String? = null,
    ogTitle: String? = null,
    ogDescription: String? = null,
    ogImageUrl: String? = null,
    expiresAt: Date? = null,
): LanderShortLink

Prop

Type

What you cannot choose from the app:

  • The slug is always random (7 characters).
  • The domain is the project's default domain.
  • The environment follows the key: a pk_test_ key creates test links, a pk_live_ key creates live links.

Fallback URLs change deferred linking

A link with an Android fallback URL sends Android users without the app to that URL instead of the Play Store, so it cannot carry an install referrer token. Leave it empty if you want deferred deep links. See Deferred links.

The result

createLink returns a LanderShortLink:

FieldTypeExample
idStringLink ID (UUID)
urlStringhttps://acme.golander.link/x7Kp2Qa
uriUriurl as an android.net.Uri
domainStringacme.golander.link
slugStringx7Kp2Qa
pathString/product/123
paramsMap<String, Any>{productId=123}
title, campaign, channelString?As sent
tagsList<String>As sent
expiresAt, createdAtDate?Parsed from the API

toString() returns the URL, so "Check this out: $link" reads naturally.

Errors

createLink checks two things before it sends anything, and throws an IllegalArgumentException when:

  • path does not start with /.
  • A params value is not a String, Number or Boolean (or is a non finite number).

It throws IllegalStateException before Lander.initialize. Everything else is checked by the API. Failures throw a LanderException:

codestatusCodeMeaning
validation_error400A field is too long or malformed (see the limits above).
destination_blocked400A fallback URL failed Lander's safety screening.
rate_limited429Too many links from this install (20 per minute) or project (60 per minute). retryAfter says when to try again.
link_quota_exceeded429The project created 1000 links in the last 24 hours.
invalid_api_key401The publishable key is wrong or revoked.
network_error, timeoutnullNo response after retries.
invalid_responsenull or 2xxThe response was not the JSON Lander sends, for example a captive portal page.

e.isRetryable is true for network errors, timeouts, invalid_response, 408, 429 (except link_quota_exceeded) and 5xx responses. e.retryAfter is a kotlin.time.Duration; Java reads getRetryAfterMillis().

The SDK retries network errors, timeouts, 408, 429 and 5xx responses up to 3 attempts in total, with a short backoff (and waits at least as long as a Retry-After header asks). It waits at most 10 seconds in total between attempts, so a share button never hangs on a long Retry-After: the LanderException comes back with retryAfter instead. link_quota_exceeded is not retried. Every attempt carries the same Idempotency-Key, and Lander replays the first successful response for a repeated key, so a retry after a lost response returns the same link instead of creating a second one.

The install ID is sent along, which is how the API applies the per install rate limit.

Next steps

On this page