> For the complete documentation index, see [llms.txt](https://legacy-docs.usesmileid.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://legacy-docs.usesmileid.com/integration-options/mobile/products/smartselfie-tm-enrollment-and-authentication.md).

# SmartSelfie™ Enrollment and Authentication

SmartSelfie™ Authentication is exposed as a flow which performs the following high level steps:

1. Displays instructions to the user
2. Requests camera permissions (if not already granted)
3. Captures and saves Liveness and Selfie images
4. Submits the job to the Smile ID API
5. Delivers the result back to the caller

{% tabs %}
{% tab title="Jetpack Compose (Android)" %}
If you are registering a user for the first time, you should use `SmileID.SmartSelfieEnrollment`

If you are authenticating a *previously registered* user, you should use `SmileID.SmartSelfieAuthentication`

```kotlin
import android.util.Log
import androidx.compose.runtime.Composable
import com.smileidentity.SmileID
import com.smileidentity.compose.SmartSelfieRegistration
import com.smileidentity.results.SmartSelfieResult

@Composable
fun SmartSelfieRegistrationExample() {
    SmileID.SmartSelfieEnrollment { result ->
        when (result) {
            is SmileIDResult.Success -> {
                val resultData = result.data
                Log.d("SmartSelfieEnrollment", "Success: $resultData")
                // SmartSelfieResult.Success contains: captured selfie file, captured liveness
                // files, and latest job status response from the API
                val (selfieFile, livenessFiles, jobStatusResponse) = resultData
            }

            is SmileIDResult.Error -> {
                // There was an error (could be denied camera permissions, network errors, etc)
                val throwable = result.throwable
                Log.w("SmartSelfieEnrollment", "Failure: $it", throwable)
            }
        }
    }
}
```

{% endtab %}

{% tab title="Fragment (Android)" %}
If you are registering a user for the first time, you should use `SmartSelfieEnrollmentFragment`

If you are authenticating a *previously registered* user, you should use `SmartSelfieAuthenticationFragment`

```kotlin
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.FragmentActivity
import com.smileidentity.fragment.SmartSelfieEnrollmentFragment


class JavaActivity : FragmentActivity() {
    private fun doSmartSelfieEnrollment() {
        val smartSelfieFragment = SmartSelfieEnrollmentFragment.newInstance()
        supportFragmentManager.setFragmentResultListener(
            SmartSelfieEnrollmentFragment.KEY_REQUEST,
            this,
        ) { _: String?, result: Bundle? ->
            val smartSelfieResult = SmartSelfieEnrollmentFragment.resultFromBundle(result!!)
            Log.v("SmartSelfieEnrollment", "Result: $smartSelfieResult")
            when (smartSelfieResult) {
                is SmileIDResult.Success -> {
                    val (selfieFile, livenessFiles, jobStatusResponse) = smartSelfieResult.data
                    // Note: Although the API submission is successful, the job status response
                    // may indicate that the job is still in progress or failed. You should
                    // check the job status response to determine the final status of the job.
                    if (jobStatusResponse.jobSuccess) {
                        Log.v("SmartSelfieEnrollment", "Job Success")
                    } else if (!jobStatusResponse.jobComplete) {
                        Log.v("SmartSelfieEnrollment", "Job Not Complete")
                    } else {
                        Log.v("SmartSelfieEnrollment", "Job Failed")
                    }
                }
                is SmileIDResult.Error -> {
                    val throwable = smartSelfieResult.throwable
                    Log.v("SmartSelfieEnrollment", "Error: " + throwable.message)
                }
            }
            supportFragmentManager
                .beginTransaction()
                .remove(smartSelfieFragment)
                .commit()
        }
        supportFragmentManager
            .beginTransaction()
            .replace(android.R.id.content, smartSelfieFragment)
            .commit()
    }
}
```

When using the Fragment approach, a convenience `resultFromBundle` static method is provided to help extract a typed object from the result Bundle.
{% endtab %}

{% tab title="Swift UI (iOS)" %}

```swift
import SwiftUI
import SmileID

struct HomeView: View, SmartSelfieResultDelegate {
@State presentAuth = false
@State presentEnroll = false

    var body: some View {
        HStack(spacing: 15) {
            Button(action: {self.presentEnroll.toggle()}) {
                Text("SmartSelfie™ Enrollment")
            }
            .sheet(isPresented: $presentEnroll, content: {
                SmileID.smartSelfieEnrollmentScreen(userId: "userID", delegate: self)
            })

            Button(action: {self.presentAuth.toggle()}) {
                Text("SmartSelfie™ Authentication")
            }
            .sheet(isPresented: $presentEnroll, content: {
                SmileID.smartSelfieAuthenticationScreen(userId: "userID", delegate: self)
            })
        }
    }

    func didSucceed(selfieImage: URL, livenessImages: [URL], apiResponse: SmartSelfieResponse?) {
        print("Successfully submitted SmartSelfie job")
    }

    func didError(error: Error) {
        print("An error occured - \(error.localizedDescription)")
    }
}
```

{% endtab %}

{% tab title="UIKit (iOS)" %}

```swift
let smartSelfieEnrollmentScreen = SmileID.smartSelfieEnrollmentScreen(...)
let uiKitController = UIHostingController(rootView: smartSelfieEnrollmentScreen)
smartSelfieScreen.modalPresentationStyle = .fullScreen
navigationController?.present(uiKitController, animated: true)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Navigator.of(context).push( //Requires Navigator.of(context).push in order to load
    MaterialPageRoute<void>(
        builder: (BuildContext context) => Scaffold(
            appBar: AppBar(title: const Text("SmileID Selfie Enrollment")),
            body: SmileIDSmartSelfieEnrollment(
                userId: "random-user-id/generated-user-id",
                // There are more parameters -- they correspond 1:1 with the native SDK parameters
                onSuccess: (String? result) {
                    // Your success handling logic
                    final snackBar = SnackBar(content: Text("Success: $result"));
                    ScaffoldMessenger.of(context).showSnackBar(snackBar);
                    Navigator.of(context).pop(); //Return flow to your app
                },
                onError: (String errorMessage) {
                    // Your error handling logic
                    final snackBar = SnackBar(content: Text("Error: $errorMessage"));
                    ScaffoldMessenger.of(context).showSnackBar(snackBar);
                    Navigator.of(context).pop(); //Return flow to your app
                }
            ),
        ),
    ),
);
```

If you are authenticating a *previously registered* user, you should use `SmileIDSmartSelfieAuthentication` Flutter widget

```dart
Navigator.of(context).push( //Requires Navigator.of(context).push in order to load
    MaterialPageRoute<void>(
        builder: (BuildContext context) => Scaffold(
            appBar: AppBar(title: const Text("SmileID Selfie Authentication")),
            body: SmileIDSmartSelfieAuthentication(
                userId: "random-user-id/generated-user-id",
                // There are more parameters -- they correspond 1:1 with the native SDK parameters
                onSuccess: (String? result) {
                    // Your success handling logic
                    final snackBar = SnackBar(content: Text("Success: $result"));
                    ScaffoldMessenger.of(context).showSnackBar(snackBar);
                    Navigator.of(context).pop(); //Return flow to your app
                },
                onError: (String errorMessage) {
                    // Your error handling logic
                    final snackBar = SnackBar(content: Text("Error: $errorMessage"));
                    ScaffoldMessenger.of(context).showSnackBar(snackBar);
                    Navigator.of(context).pop(); //Return flow to your app
                }
            ),
        ),
    ),
);
```

{% endtab %}

{% tab title="React Native" %}
{% hint style="info" %}
:warning: **Note:** Recommend wrapping this in a component that can be navigated to and out of view due to a known issue with views displaying dialogs particularly on failure and the dialog keeps showing,
{% endhint %}

```typescript
<SmileIDSmartSelfieEnrollmentView
  userId="random-user-id/generated-user-id"
  allowAgentMode={false}
  forceAgentMode={false}
  style={{ width: '100%', height: '100%' }}
  onResult={(event) => {
    setResult(event.nativeEvent.result);
  }}
/>
```

If you are authenticating an existing user you should use SmileIDSmartSelfieAuthenticationView

```typescript
<SmileIDSmartSelfieAuthenticationView
  userId="random-user-id/generated-user-id"
  allowAgentMode={false}
  forceAgentMode={false}
  style={{ width: '100%', height: '100%' }}
  onResult={(event) => {
    setResult(event.nativeEvent.result);
  }}
/>
```

On `onResult`, you will receive a JSON string following the structure:

```json
{
  "selfieFile": "<path to selfie file>",
  "livenessFiles": [
    "<path to liveness file>",
    "<path to liveness file>"
  ],
  "apiResponse": {
    "code": "...",
    "created_at": "",
    "job_id": "",
    "job_type": "",
    "message": "",
    "partner_id": "",
    "partner_params": "",
    "status": "",
    "updated_at": "",
    "user_id": ""
  }
}
```

{% endtab %}

{% tab title="React Native Expo" %}
{% hint style="info" %}
:warning: **Note:** Recommend wrapping this in a component that can be navigated to and out of view due to a known issue with views displaying dialogs particularly on failure and the dialog keeps showing,
{% endhint %}

Before using the widgets, define a `SmartSelfieParams` object to configure the SmartSelfie™ flow:

```typescript
import { SmartSelfieParams } from 'react-native-expo';

const smartSelfieParams: SmartSelfieParams = {
  // userId: 'user123', // Optional user ID
  // jobId: 'job456', // Optional job ID
  allowNewEnroll: false,
  allowAgentMode: true,
  showAttribution: true,
  showInstructions: true,
  skipApiSubmission: false,
  useStrictMode: false,
  extraPartnerParams: {
    'custom_param_1': 'value1',
    'custom_param_2': 'value2'
  }
};
```

```typescript
 <SmileIDSmartSelfieEnrollmentView
    style={styles.nativeView}
    params={smartSelfieParams}
    onResult={handleSuccessResult}
    onError={handleError}
/>
```

If you are authenticating an existing user you should use SmileIDSmartSelfieAuthenticationView

```typescript
 <SmileIDSmartSelfieAuthenticationView
    style={styles.nativeView}
    params={smartSelfieParams}
    onResult={handleSuccessResult}
    onError={handleError}
/>
```

On `onResult`, you will receive a JSON string following the structure:

```json
{
  "selfieFile": "<path to selfie file>",
  "livenessFiles": [
    "<path to liveness file>",
    "<path to liveness file>"
  ]
}
```

{% endtab %}
{% endtabs %}

### Arguments

#### `userId`

The user ID to associate with the SmartSelfie™ Registration. Most often, this will correspond to a unique User ID within your own system. (If not provided at time of Registration, a random user ID will be generated. This field is required for Authentication)

#### `jobId`

The job ID to associate with the SmartSelfie™ Registration. Most often, this will correspond to a unique Job ID within your own system. If not provided, a random job ID will be generated.

#### `allowAgentMode`

Whether to allow *Agent Mode* or not. If allowed, a switch will be displayed allowing toggling between the back camera and front camera. If not allowed, only the front camera will be used.

#### `forceAgentMode`

Whether to force Agent Mode. If forced, the back camera will always be used without showing a toggle switch to the user. Takes precedence over `allowAgentMode`.

#### `allowNewEnroll`

Allows a partner to enroll the same user id again

#### `showAttribution`

Whether to show the Smile ID attribution or not on the Instructions screen

**`showInstructions`**

Whether to deactivate capture screen's instructions for SmartSelfie.

#### `skipApiSubmission`

Whether to capture images and not Submit to the SmileID api, this will return file paths which can be retrieved for later use.

#### `extraPartnerParams`

Custom values specific to partners passed as an immutable map

#### `colorScheme`

See [Customization](/integration-options/mobile/theming.md#theming)

#### `typography`

See [Customization](/integration-options/mobile/theming.md#theming)

#### `onResult` (Android)

Callback to be invoked when the SmartSelfie™ Registration is complete. The result itself is a `SmileIDResult` which can either be a `SmileIDResult.Success` or `SmileIDResult.Error`

#### `delegate` (iOS)

This is the delegate object that is notifed when there is a result from the SmartSelfie™ flow. This class has to conform to `SmartSelfieResultDelegate` and implement the delegate methods\
`func didSucceed(selfieImage: Data, livenessImages: [Data], jobStatusResponse: JobStatusReponse)` and `func didError(error: Error)`


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://legacy-docs.usesmileid.com/integration-options/mobile/products/smartselfie-tm-enrollment-and-authentication.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
