---
title: Implement a user profile service using the Swift SDK
slug: feature-experimentation/docs/configure-a-user-profile-service-swift
docTags: 
createdAt: 2026-08-05T20:40:00.000Z
---

Use a **User Profile Service** to persist information about your users and ensure variation assignments are sticky. For example, if you are working on a backend website, you can create an implementation that reads and saves user profiles from a Redis or Memcached store.

The Swift SDK defaults to a User Profile Service that stores this state directly on the device. See the [Swift SDK User Profile Service](https://github.com/optimizely/swift-sdk/blob/master/Sources/Customization/DefaultUserProfileService.swift).

To read a customer's user profile, call `lookup(userId:)` on the `OPTUserProfileService` instance that you passed to `OptimizelyClient`. Alternatively, call it on a `DefaultUserProfileService` instance.

If the User Profile Service does not bucket a user as you expect, then check whether other flags are overriding the bucketing. For information, see [How bucketing works](docId\:eH-UMm_rOn_GdGDGLV6__).

## Implement a service

To implement a custom User Profile Service, rather than using the default service provided by the Swift SDK, refer to the following code samples. The service needs to expose two functions with the following signatures:

- `lookup` – Takes a user ID string and returns a user profile matching The following schema.
- `save` – Takes a user profile and persists it.

If you want to use the User Profile Service purely for tracking purposes and not sticky bucketing, you can implement only the `save` method (always return `nil` from `lookup`).

```swift
class CustomUserProfileService: OPTUserProfileService {
    required init() {}

    func lookup(userId: String) -> UPProfile? {
        
        // Retrieve and return user profile
        // Replace with userprofile variable
        
        return nil
    }
    
    open func save(userProfile: UPProfile) {
        
        // save user profile
    }
}

let userProfileService = CustomUserProfileService()

let optimizely = OptimizelyClient(sdkKey: sdkKey,
                              userProfileService: userProfileService)
```

The following code example shows the JSON schema for the user profile object.

Use `experiment_bucket_map` to override the default bucketing behavior and define an alternate experiment variation for a given user. For each experiment that you want to override, add an object to the map. Use the experiment ID as the key and include a `variation_id` property that specifies the desired variation. If there isn't an entry for an experiment, then the default bucketing behavior persists.

In The following example, `^[a-zA-Z0-9]+$` is the experiment ID.

```json
{
  "title": "UserProfile",
  "type": "object",
  "properties": {
    "user_id": {"type": "string"},
    "experiment_bucket_map": {"type": "object",
                              "patternProperties": {
                                 "^[a-zA-Z0-9]+$": {"type": "object",
                                                    "properties": {"variation_id": {"type":"string"}},
                                                    "required": ["variation_id"]}
                               }
                             }
  },
  "required": ["user_id", "experiment_bucket_map"]
}
```

The Swift SDK uses the User Profile Service you provide to override Optimizely Feature Experimentation's default bucketing behavior in cases when an experiment assignment has been saved. The User Profile Service will persist variation assignments across app updates. However, the User Profile Service will not persist variation assignments across app re-installs.

Decisions for Contextual Multi-Armed Bandit (CMAB) experiments are not saved to the User Profile Service.

When implementing your own User Profile Service, you should loading the user profiles into the User Profile Service on initialization and avoiding performing expensive, blocking lookups on the lookup function to minimize the performance impact of incorporating the service.

When implementing in a multi-server or stateless environment, you should using this interface with a backend like [Cassandra](http://cassandra.apache.org/) or [Redis](https://redis.io/). You can decide how long you want to keep your sticky bucketing around by configuring these services.
