> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryrollup.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get access, add the Rollup SDK to your iOS app, and run your first search, query and profile.

This guide takes you from a new developer account to a first search on your own iPhone.

<Warning>
  Test on a real iPhone with iOS 26 or later. The SDK does not run in the iOS Simulator.
</Warning>

## Get access

<Steps>
  <Step title="Sign in to the developer dashboard">
    Go to [tryrollup.com/developers](https://www.tryrollup.com/developers) and sign in with your email. Rollup sends you a sign-in link. Your first sign-in creates a developer account that waits for Rollup to approve it. While it waits, the dashboard shows "Your access is being reviewed".
  </Step>

  <Step title="Create an app">
    Once your account is approved, create an app with a name, your Apple Team ID (10 characters) and your app's bundle ID. The app gets a publishable key that starts with `rk_live_`.
  </Step>

  <Step title="Wait for the app to be approved">
    A new app also waits for approval. Until Rollup approves it, the server answers every request with the error `app_pending`. Rollup emails you when your account or app is approved, or if it is not.
  </Step>
</Steps>

The publishable key ships inside your app, so it is not a secret. What proves a request comes from your app is App Attest, which Rollup checks against your Team ID and bundle ID.

## Add the SDK

The SDK ships as a binary framework, `Rollup.xcframework`, that you add with Swift Package Manager or CocoaPods. It requires iOS 26.

<Tabs>
  <Tab title="Swift Package Manager">
    In Xcode, choose File, then Add Package Dependencies, and enter the package URL. Add the `Rollup` library to your app target.

    ```text theme={null}
    https://github.com/KINT-AI/rollup-ios-sdk
    ```

    Or add it to `Package.swift`:

    ```swift Package.swift theme={null}
    .package(url: "https://github.com/KINT-AI/rollup-ios-sdk", from: "0.1.0")
    ```
  </Tab>

  <Tab title="CocoaPods">
    Rollup is not on CocoaPods trunk, which stops accepting pods on December 2, 2026. Point your Podfile at Rollup's podspec:

    ```ruby Podfile theme={null}
    pod 'Rollup', :podspec => 'https://raw.githubusercontent.com/KINT-AI/rollup-ios-sdk/0.1.0/Rollup.podspec'
    ```
  </Tab>
</Tabs>

The framework is dynamic, signed by Rollup, and includes its own privacy manifest. Xcode embeds it in your app.

Rollup's enums, such as `IndexingState` and `RollupError.Code`, can gain cases in later versions. When you switch over one, include a `default` or `@unknown default` case.

## Configure your app target

The SDK checks these entries when you call `configure`, and throws an error that names any that are missing.

<Steps>
  <Step title="Photos usage description">
    Add `NSPhotoLibraryUsageDescription` to your Info.plist with text that tells the person why your app reads their photos.
  </Step>

  <Step title="Background task identifiers">
    Add both identifiers below to `BGTaskSchedulerPermittedIdentifiers`. The first lets indexing continue in the background after the person starts it; the second keeps the index up to date later.
  </Step>

  <Step title="Background processing mode">
    Add `processing` to `UIBackgroundModes`. In Xcode, this is the **Background processing** option of the Background Modes capability.
  </Step>

  <Step title="App Attest">
    Add the **App Attest** capability to your target. `configure` cannot check for it; without it, the device cannot register, and the first call that needs Rollup's server throws `appAttestFailed`, naming the missing capability.
  </Step>
</Steps>

```xml Info.plist theme={null}
<key>NSPhotoLibraryUsageDescription</key>
<string>Your photos help personalize the app. They stay on your iPhone.</string>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER).rollup.indexing.*</string>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER).rollup.update</string>
</array>
<key>UIBackgroundModes</key>
<array>
    <string>processing</string>
</array>
```

Development-signed builds attest in Apple's development App Attest environment, which Rollup accepts, so your real key works from your first build on a device.

## Configure the SDK

Register the background tasks and configure the SDK when your app starts. `registerBackgroundTasks` must run before your app finishes launching.

```swift MyApp.swift theme={null}
import SwiftUI
import Rollup

@main
struct MyApp: App {
    init() {
        Rollup.registerBackgroundTasks()
        do {
            try Rollup.configure(publishableKey: "rk_live_...")
        } catch {
            print("Rollup could not start: \(error)")
        }
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}
```

By default the SDK indexes the last three months of photos, screenshots and videos, and keeps adding new ones. To change what it indexes, pass `IndexOptions`. See [Index options](/guides/index-options).

## Ask for Photos access

Call `requestPhotoAccess` from a screen where the person has just chosen to turn the feature on. iOS shows its Photos prompt once.

```swift theme={null}
let access = await Rollup.shared.requestPhotoAccess()
if access == .authorized || access == .limited {
    // Indexing has started.
}
```

When the person grants access, the first index starts at once. It downloads about 225 MB of models on first run, then indexes the newest photos first. If the person leaves your app, indexing continues in the background, and iOS shows its progress. See [Background indexing](/guides/background-indexing).

With limited Photos access, the SDK indexes only the photos the person selected.

## Watch indexing

`indexing.states` reports the current state and every change after it.

```swift theme={null}
for await state in Rollup.shared.indexing.states {
    switch state {
    case .downloadingAssets(let fraction):
        print("Downloading models: \(Int(fraction * 100))%")
    case .indexing(let indexed, let total, let searchable):
        print("Indexed \(indexed) of \(total), searchable: \(searchable)")
    case .ready(let photos, _):
        print("Ready with \(photos) photos")
    case .failed(let error):
        print("Indexing failed: \(error)")
    default:
        break
    }
}
```

Search, query and profile work as soon as `state.isSearchable` is true: the index answers from the photos it holds so far, newest first, while older ones fill in.

## Search, ask and fill a profile

```swift theme={null}
let results = try await Rollup.shared.search("ramen in Tokyo last spring")
for result in results.results {
    print(result.id, result.date as Any, result.location?.city as Any)
}

let answer = try await Rollup.shared.query("Where do I eat most?")
print(answer.text)

let schema = Data("""
{
  "type": "object",
  "properties": {
    "favorite_cuisine": { "type": "string", "description": "The cuisine they eat most often" },
    "drinks_coffee": { "type": "boolean" }
  }
}
""".utf8)
let profile = try await Rollup.shared.profile(schema: schema)
print(String(decoding: profile.json, as: UTF8.self))
```

`search` runs on the iPhone. `query` and `profile` need a network connection, and each takes a few seconds to about 20 seconds.

<Warning>
  Before your app calls `query` or `profile`, it must tell the person that results of their photo index are sent to Rollup and its model provider, and get their permission. See [Privacy and App Review](/guides/privacy).
</Warning>

## Next steps

<Columns cols={2}>
  <Card title="Index options" icon="sliders-horizontal" href="/guides/index-options">
    Choose the time window, media and places.
  </Card>

  <Card title="Profile schemas" icon="braces" href="/guides/profile">
    What a schema can ask for and what comes back.
  </Card>

  <Card title="Keys and revocation" icon="key" href="/guides/keys-and-revocation">
    Rotate keys and understand what happens when access stops.
  </Card>

  <Card title="Troubleshooting" icon="life-buoy" href="/guides/troubleshooting">
    Common errors and what they mean.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.