# Android SDK (Beta)

{% hint style="info" %}
If you're using an AI tool such as Cursor, ChatGPT Codex, or Claude Code to help you implement GrowSurf, we recommend utilizing our [MCP server](https://docs.growsurf.com/build-with-ai).
{% endhint %}

## Install

The core library is lightweight, adding roughly \~1 MB to your Android app (attribution adapters add only tens of KB each).

Add the core SDK from Maven Central. Choose one install path.

{% tabs %}
{% tab title="Kotlin DSL" %}

```kotlin
repositories {
    mavenCentral()
}

dependencies {
    implementation("com.growsurf:growsurf-android-sdk:0.3.0")
}
```

{% endtab %}

{% tab title="Groovy" %}

```groovy
repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.growsurf:growsurf-android-sdk:0.3.0'
}
```

{% endtab %}
{% endtabs %}

If you use Branch, Adjust, AppsFlyer, or Singular, add the matching GrowSurf adapter.

{% tabs %}
{% tab title="Kotlin DSL" %}

```kotlin
dependencies {
    implementation("com.growsurf:growsurf-android-sdk-attribution-branch:0.3.0")
    implementation("com.growsurf:growsurf-android-sdk-attribution-adjust:0.3.0")
    implementation("com.growsurf:growsurf-android-sdk-attribution-appsflyer:0.3.0")
    implementation("com.growsurf:growsurf-android-sdk-attribution-singular:0.3.0")
}
```

{% endtab %}

{% tab title="Groovy" %}

```groovy
dependencies {
    implementation 'com.growsurf:growsurf-android-sdk-attribution-branch:0.3.0'
    implementation 'com.growsurf:growsurf-android-sdk-attribution-adjust:0.3.0'
    implementation 'com.growsurf:growsurf-android-sdk-attribution-appsflyer:0.3.0'
    implementation 'com.growsurf:growsurf-android-sdk-attribution-singular:0.3.0'
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Keep your provider's SDK setup in your app. The GrowSurf adapter passes provider callback data into GrowSurf.
{% endhint %}

### Initialize

Enable Mobile SDK access in your GrowSurf program on the instructions page, then configure the SDK once when your app starts or before your first GrowSurf call.

* Find `campaignId` in your GrowSurf program dashboard. It is the 6-character program ID, such as `p9josq`.
* Find `publicKey` in *Program Editor > 5. Installation > Instructions page > Step 1. Android > Configure SDK*.

```kotlin
import com.growsurf.sdk.GrowSurfSdk

val growsurf = GrowSurfSdk.configure(
    context = context,
    campaignId = "p9josq",
    publicKey = "pk_mobile",
)
```

{% hint style="info" %}
Native apps use a public Mobile SDK key, which can safely be exposed. This is different than your REST API key on your backend, which you should always keep secret.
{% endhint %}

***

## Track referrals

Tracking referrals entails capturing attribution and creating new referred participants.

### Capture attribution

Capture referral attribution before you create the referred friend's participant record.

{% stepper %}
{% step %}
**For direct app links that open your installed app:**

```kotlin
intent.data?.let { uri ->
    growsurf.handleDeepLink(uri)
}
```

{% hint style="info" %}
**Already support deep links?** If you use an attribution provider (Branch, AppsFlyer, Adjust, Singular) or otherwise open your app from links, this is already set up — just forward the opened `Intent`'s URI to `handleDeepLink(uri)`.

**Starting from scratch?** Add a custom-scheme `<intent-filter>` (`android:scheme`) to your launch Activity in `AndroidManifest.xml` — the quickest path, no domain needed — and/or set up Android App Links (`android:autoVerify="true"` plus an `assetlinks.json` hosted on a domain you control) for verified `https` links. Then read `intent.data` in `onCreate`/`onNewIntent` and call `handleDeepLink(uri)` inside a coroutine scope.
{% endhint %}
{% endstep %}

{% step %}
**For deferred deep links from an attribution provider:**

View [Adapter docs](https://docs.growsurf.com/developer-tools/android-sdk/attribution-providers#adapters) for your specific provider setup instructions.

{% hint style="info" %}
For Google Play installs, [`addReferredParticipant()`](https://docs.growsurf.com/developer-tools/android-sdk/api-reference#add-referred-participant) checks Play Install Referrer once when no explicit or pending attribution exists. You can still call [`handleDeferredDeepLink()`](https://docs.growsurf.com/developer-tools/android-sdk/api-reference#handle-deferred-deep-link) yourself if you want to inspect attribution earlier:

```kotlin
lifecycleScope.launch {
    growsurf.handleDeferredDeepLink()
}
```

{% endhint %}
{% endstep %}
{% endstepper %}

### Create a referred participant

Use [`addReferredParticipant()`](https://docs.growsurf.com/developer-tools/android-sdk/api-reference#add-referred-participant) for referred signups. This is typically where new users sign up in your app.

The SDK validates saved, explicit, or Play Install Referrer attribution and only creates the participant when the referral code is valid.

```kotlin
// Only creates a referred participant if the referral code is valid
val created = growsurf.addReferredParticipant(
    GrowSurfParticipantInput(
        email = "person@example.com",
        firstName = "Ada",
        lastName = "Lovelace",
        metadata = mapOf("plan" to "pro"), // Optional, saved as participant metadata
        // The referral code and mobile instance ID (for anti-fraud) are passed automatically
    )
)

val participant = created.participant
```

***

## Generate referral links for your users

Generating referral links to users in your app entails generating a participant token by using the GrowSurf API, then opening the GrowSurf window.

### Generate a participant token

To allow authenticated access to your logged-in users, you must call the GrowSurf backend to generate a participant token.

{% stepper %}
{% step %}
**Call backend endpoint** [**create a mobile participant token.**](/developer-tools/rest-api/api-reference.md#create-mobile-participant-token)

Here is an example `cURL` command:

```bash
curl -X POST "https://api.growsurf.com/v2/campaign/YOUR_PROGRAM_ID/mobile-participant-token" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
   "email": "person@example.com",
   "firstName": "Ada",
   "lastName": "Lovelace",
   "mobileInstanceId": "5f7d0f4c-3e7c-4aa9-8c41-d81d998f0bb1",
   "ipAddress": "203.0.113.10",
   "metadata": {
      "plan": "pro"
   }
}'
```

Only `email` is required. `firstName`, `lastName`, `mobileInstanceId`, and `ipAddress` are optional but recommended for anti-fraud. `metadata` is optional and is not used by GrowSurf.

{% hint style="info" %}
Using TypeScript, Python, PHP, Ruby, or Java for your backend? Use an official [GrowSurf API Library](https://docs.growsurf.com/developer-tools/rest-api/api-libraries).
{% endhint %}

**Optional:** To get `mobileInstanceId`, which is used for anti-fraud purposes, use the SDK method [`getMobileInstanceId()`](https://docs.growsurf.com/developer-tools/android-sdk/api-reference#get-mobile-instance-id).

This will create a new participant or return an existing one, along with a participant token that allows authenticated calls.
{% endstep %}

{% step %}
**Pass it to the app, then store in the SDK via** [**`setParticipantToken()`**](https://docs.growsurf.com/developer-tools/android-sdk/api-reference#set-participant-token)**.**

Here is example SDK code:

```kotlin
// getMobileInstanceId() is a suspend function, so call it from a coroutine.
lifecycleScope.launch {
    val mobileInstanceId = growsurf.getMobileInstanceId() // Used for anti-fraud (optional)
    val backendResponse = api.createMobileParticipantToken(
        email = user.email,
        mobileInstanceId = mobileInstanceId,
    )
    val participantToken = backendResponse.participantToken

    growsurf.setParticipantToken(participantToken)
}
```

{% endstep %}
{% endstepper %}

### Show the GrowSurf window

<div align="left"><figure><img src="/files/ZZTs4QzmyOgwxxQvysUo" alt="" width="188"><figcaption></figcaption></figure> <figure><img src="/files/NAy8ur4aaGaODzNpZpFq" alt="" width="188"><figcaption></figcaption></figure> <figure><img src="/files/ppeQCsy9TG8m74eHK78T" alt="" width="188"><figcaption></figcaption></figure></div>

The GrowSurf window allows your participants to view/share their referral link and track the status of their referrals and rewards.

Call [`presentGrowSurfWindow()`](https://docs.growsurf.com/developer-tools/android-sdk/api-reference#present-growsurf-window) from your own button, menu item, or referral screen. Set the `identity` parameter to [`GrowSurfWindowIdentity.ExistingParticipantToken()`](https://docs.growsurf.com/developer-tools/android-sdk/models-and-errors#growsurfwindowidentity), which will use the participant token you generated above.

```kotlin
growsurf.presentGrowSurfWindow(
    activity = this,
    identity = GrowSurfWindowIdentity.ExistingParticipantToken(participantToken),
    theme = GrowSurfWindowTheme(
        primaryColor = 0xFF13795B,
        presentationStyle = GrowSurfWindowPresentationStyle.AUTOMATIC,
    ),
    callbacks = GrowSurfWindowCallbacks(
        onShareTracked = { type ->
            Log.d("GrowSurf", "Share tracked: $type")
        },
        onError = { error ->
            Log.e("GrowSurf", "GrowSurf window error", error)
        },
    ),
)
```

***

## \[Optional] Google Contacts invites <a href="#google-contacts" id="google-contacts"></a>

<div align="left"><figure><img src="/files/ZZTs4QzmyOgwxxQvysUo" alt="" width="188"><figcaption></figcaption></figure> <figure><img src="/files/L0tXmp3gdKjKK38P9P8T" alt="" width="187"><figcaption></figcaption></figure> <figure><img src="/files/kO25oflJgrA0x4CuMyc4" alt="" width="187"><figcaption></figcaption></figure></div>

Only needed when Google Contacts invites are enabled for your program. When a participant taps the Google Contacts button, the GrowSurf window takes them through Google's sign-in to grant access to their contacts (read-only) — the same experience as on iOS.

Unlike iOS, there is **no in-app code to add** on Android: the required Google Sign-In library is bundled with the SDK, and there is no URL scheme or URL forwarding to configure. The only requirement is a correctly configured Google Cloud OAuth client for your app.

{% stepper %}
{% step %}
**Create an Android OAuth client** as part of the [Google Cloud setup](https://support.growsurf.com/article/343-how-to-set-up-google-contacts-address-book). Set the application type to **Android** and register it with your app's **package name** and its **SHA-1 signing-certificate fingerprint**. Without this, the consent screen fails with a `DEVELOPER_ERROR`.
{% endstep %}

{% step %}
**Get your SHA-1 fingerprint.** The quickest way is the Gradle signing report, which prints the SHA-1 for every build variant:

```bash
./gradlew signingReport
```

Or read it directly from a keystore with `keytool`:

```bash
# Debug keystore (default location)
keytool -list -v \
  -keystore ~/.android/debug.keystore \
  -alias androiddebugkey -storepass android -keypass android

# Release keystore
keytool -list -v \
  -keystore /path/to/your/release.keystore \
  -alias your-key-alias
```

Register **both** your debug and release SHA-1 fingerprints so Google Contacts works in development and production.
{% endstep %}

{% step %}
**Using Google Play App Signing?** Register the SHA-1 of the **app signing key** shown in **Play Console → Test and release → App integrity → App signing key certificate** — not just your upload key. Otherwise the consent screen will fail in production even after the steps above.
{% endstep %}
{% endstepper %}

***

## Log out

If your user logs out of your app, call [`shutdown()`](https://docs.growsurf.com/developer-tools/android-sdk/api-reference#shutdown) to remove all participant data from the device:

```kotlin
growsurf.shutdown()
```

***

## Next steps

{% content-ref url="/pages/GhQfB3WsJlg97Hqpy7n9" %}
[Attribution Providers](/developer-tools/android-sdk/attribution-providers.md)
{% endcontent-ref %}

{% content-ref url="/pages/XLxytePFauV0nWRkLmv8" %}
[API Reference](/developer-tools/android-sdk/api-reference.md)
{% endcontent-ref %}

{% content-ref url="/pages/3NzBu6Jtu7Cvd7wWg7L1" %}
[Models and Errors](/developer-tools/android-sdk/models-and-errors.md)
{% endcontent-ref %}

{% content-ref url="/pages/exdoU1ymhoG3SfIjmIsO" %}
[Getting Started for Native Mobile](/getting-started-for-native-mobile.md)
{% endcontent-ref %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.growsurf.com/developer-tools/android-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
