# iOS 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 \~2.6 MB (uncompressed device binary) to your iOS app (attribution adapters add only tens of KB each).&#x20;

Choose one install path.

{% tabs %}
{% tab title="CocoaPods" %}
Add the SDK from the public `v0.3.0` podspec:

```ruby
growsurf_podspec = 'https://raw.githubusercontent.com/growsurf/growsurf-ios-sdk-distribution/v0.3.0/GrowSurfSDK.podspec'

pod 'GrowSurfSDK', :podspec => growsurf_podspec
```

Optional attribution adapter subspecs:

```ruby
pod 'GrowSurfSDK/BranchAttribution', :podspec => growsurf_podspec
pod 'GrowSurfSDK/AdjustAttribution', :podspec => growsurf_podspec
pod 'GrowSurfSDK/AppsFlyerAttribution', :podspec => growsurf_podspec
pod 'GrowSurfSDK/SingularAttribution', :podspec => growsurf_podspec
```

The optional `GrowSurfGoogleContacts` product additionally pulls in Google Sign-In, so add it only if you want the native in-app Google contacts sign-in sheet:

```ruby
pod 'GrowSurfSDK/GrowSurfGoogleContacts', :podspec => growsurf_podspec
```

{% endtab %}

{% tab title="Swift Package Manager" %}
In Xcode, add the public binary package repository:

```
https://github.com/growsurf/growsurf-ios-sdk-distribution.git
```

Choose version `0.3.0` or later, then add the `GrowSurfSDK` product to your app target.

For a `Package.swift` target:

```swift
dependencies: [
    .package(url: "https://github.com/growsurf/growsurf-ios-sdk-distribution.git", from: "0.3.0"),
],
targets: [
    .target(
        name: "YourApp",
        dependencies: [
            .product(name: "GrowSurfSDK", package: "growsurf-ios-sdk-distribution"),
        ]
    ),
]
```

Optional attribution adapter products are available from the same package:

* `GrowSurfBranchAttribution`
* `GrowSurfAdjustAttribution`
* `GrowSurfAppsFlyerAttribution`
* `GrowSurfSingularAttribution`

The optional `GrowSurfGoogleContacts` product additionally pulls in Google Sign-In, so add it only if you want the native in-app Google contacts sign-in sheet.
{% endtab %}

{% tab title="Manual XCFramework" %}

1. Download `GrowSurfSDK.xcframework.zip` from the public [`v0.3.0` release](https://github.com/growsurf/growsurf-ios-sdk-distribution/releases/tag/v0.3.0).
2. Unzip it and drag `GrowSurfSDK.xcframework` into your Xcode project.
3. In your app target, set `GrowSurfSDK.xcframework` to **Embed & Sign**.
4. Add optional adapter XCFrameworks the same way when you use Branch, Adjust, AppsFlyer, or Singular helpers (and add optional adapter for Google Contacts if you want the native in-app Google contacts sign-in sheet).
   {% endtab %}
   {% endtabs %}

{% hint style="info" %}
If you use Branch, Adjust, AppsFlyer, or Singular, add the matching GrowSurf adapter and keep your provider's SDK setup in your app.
{% 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. iOS > Configure SDK*.

```swift
import GrowSurfSDK

let growsurf = GrowSurf.configure(
    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:**

```swift
if let url {
    try await growsurf.handleDeepLink(url)
}
```

{% 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 URL to `handleDeepLink(url)`.

**Starting from scratch?** Register a custom URL scheme (`CFBundleURLSchemes` in `Info.plist`) — the quickest path, no domain needed — and/or configure Universal Links (Associated Domains entitlement) for nicer `https` links, which require a domain you control. Then call `handleDeepLink(url)` from your app's URL-open handler (SwiftUI `.onOpenURL` or `application(_:open:options:)`).
{% endhint %}
{% endstep %}

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

Unlike Android (which reads the Play Install Referrer for native deferred attribution), iOS has no native deferred deep link mechanism, so deferred attribution is delegated to your attribution provider (e.g., Branch, AppsFlyer). View [Adapter docs](https://docs.growsurf.com/developer-tools/ios-sdk/attribution-providers#adapters) for your specific provider setup instructions.
{% endstep %}
{% endstepper %}

### Create a referred participant

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

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

```swift
// Only creates a referred participant if the referral code is valid
let created = try await growsurf.addReferredParticipant(
    .init(
        email: "person@example.com",
        firstName: "Ada",
        lastName: "Lovelace",
        metadata: ["plan": "pro"] // Optional, saved as participant metadata
        // The referral code and mobile instance ID (for anti-fraud) are passed automatically
    )
)

let 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 [`mobileInstanceId()`](https://docs.growsurf.com/developer-tools/ios-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/ios-sdk/api-reference#set-participant-token)**.**

Here is example SDK code:

```swift
let mobileInstanceId = try await growsurf.mobileInstanceId() // Used for anti-fraud (optional)
let backendResponse = try await api.createMobileParticipantToken(
    email: user.email,
    mobileInstanceId: mobileInstanceId
)
let participantToken = backendResponse.participantToken

try await growsurf.setParticipantToken(participantToken)
```

{% endstep %}
{% endstepper %}

### Show the GrowSurf window

<div align="left"><figure><img src="/files/vGVp8AZN5tbayyFVkxks" alt="" width="188"><figcaption></figcaption></figure> <figure><img src="/files/8FwQnM1Vl2glf35ZnzbE" alt="" width="188"><figcaption></figcaption></figure> <figure><img src="/files/5AQKI2yUBMFXHb57Avr4" 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/ios-sdk/api-reference#present-growsurf-window) from your own button, menu item, or referral screen. Set the `identity` parameter to [`.existingParticipantToken()`](https://docs.growsurf.com/developer-tools/ios-sdk/models-and-errors#growsurfwindowidentity), which will use the participant token you generated above.

```swift
growsurf.presentGrowSurfWindow(
    from: viewController,
    identity: .existingParticipantToken(participantToken),
    theme: GrowSurfWindowTheme(
        primaryColorHex: "#13795B",
        presentationStyle: .automatic
    ),
    callbacks: GrowSurfWindowCallbacks(
        onShareTracked: { type in
            print("Share tracked: \(type)")
        },
        onError: { error in
            print(error.localizedDescription)
        }
    )
)
```

***

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

<div align="left"><figure><img src="/files/lQkax8mjoV7S1Jw2HI9p" alt="" width="188"><figcaption></figcaption></figure> <figure><img src="/files/ZROHSVtl41CI7D0Cd95a" alt="" width="188"><figcaption></figcaption></figure></div>

Only needed when Google Contacts invites are enabled for your program. When enabled, the native GrowSurf window can read the participant's Google contacts (read-only) so they can pick people to invite.

This works **out of the box** — the core `GrowSurfSDK` uses a dependency-free external-browser sign-in flow, so there is **no extra dependency to install** for the default experience.

To use the **native in-app Google Sign-In sheet** instead (a smoother flow that doesn't leave your app), add the optional `GrowSurfGoogleContacts` product. It bundles Google Sign-In, so it is kept out of the core SDK — apps that don't use it never link GoogleSignIn.

{% tabs %}
{% tab title="CocoaPods" %}

```ruby
pod 'GrowSurfSDK/GoogleContacts', :podspec => growsurf_podspec
```

{% endtab %}

{% tab title="Swift Package Manager" %}
Add the `GrowSurfGoogleContacts` product from the same `growsurf-ios-sdk-distribution` package to your app target (alongside `GrowSurfSDK`).
{% endtab %}
{% endtabs %}

First complete the [Google Cloud setup](https://support.growsurf.com/article/343-how-to-set-up-google-contacts-address-book) to create your OAuth client and add your iOS Client ID and reversed-client-ID URL scheme to your GrowSurf campaign. The steps below are the additional in-app setup the in-app Google Sign-In sheet needs — without them the in-app sign-in will fail even when your campaign is configured correctly.

{% stepper %}
{% step %}
**Enable the in-app GoogleSignIn flow** at app startup, before opening a GrowSurf window that offers Google contacts import:

```swift
import GrowSurfGoogleContacts

GrowSurfGoogleContacts.enable()
```

{% endstep %}

{% step %}
**Register your Google reversed-client-ID URL scheme** in `Info.plist`.

Add a `CFBundleURLTypes` entry whose `CFBundleURLSchemes` value is your reversed client ID (the `REVERSED_CLIENT_ID` from your `GoogleService-Info.plist` / OAuth client, in the form `com.googleusercontent.apps.XXXXXXXX`).
{% endstep %}

{% step %}
**Forward incoming URLs to GrowSurf** from your app's URL-open handler so the Google Sign-In callback is handled:

```swift
// SwiftUI
.onOpenURL { url in
    GrowSurf.handleGoogleSignInURL(url)
}

// UIKit
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
    GrowSurf.handleGoogleSignInURL(url)
}
```

{% endstep %}
{% endstepper %}

Either way, the SDK requests only the `contacts.readonly` scope and imports the participant's primary Google connections.

***

## Log out

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

```swift
try await growsurf.shutdown()
```

***

## Next steps

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

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

{% content-ref url="/pages/slZUcKYhVJInEALri596" %}
[Models and Errors](/developer-tools/ios-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/ios-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.
