Second question relating to <the above >context Th...
# ask-questions
b
Second question relating to the above context The Swift SDK uses caching by default according to the documentation, however when we create a new growthbook client for a new session ( logout and login, or app restart ), we see the SDK making a new feature request PRIOR TO the backgroundSync sub. I expect the backgroundSync sub request to be established first, and then the features to be loaded ONLY IF something has changed since the last sync. Is there some additional config/gotcha that might explain that behaviour?
👀 1
p
Hi Let us check that. And we'll get back to you
thankyou 1
You're right - currently, every time a new SDK instance is created, it calls
refreshCache()
which makes an HTTP GET to
/api/features/{clientKey}
before opening the SSE connection. The SDK does have a TTL-based cache internally, but the TTL is held in memory and resets to nil on each new SDK instance. So on every app launch or new login session, the cache is always considered expired, and a full network fetch fires regardless of the
ttlSeconds
value. What you can do right now: In the latest SDK version (1.1.0), Offline Mode was added. If you pass a pre-fetched features payload via the
features
parameter in the builder, the SDK will skip the network fetch entirely at init:
Copy code
let cachedPayload: Data = ... // from UserDefaults, file cache, etc.
GrowthBookBuilder(
    apiHost: "<https://cdn.growthbook.io>",
    clientKey: "sdk-abc123",
    attributes: userAttributes,
    features: cachedPayload,
    trackingCallback: { _, _ in },
    backgroundSync: true
).initializer()
This eliminates the init-time CDN request. You'd need to persist the payload on your side (e.g., save it to UserDefaults or a file when it arrives via SSE or refreshCache, then pass it back on next init). If you want to minimize CDN requests even further, you can also set
backgroundSync: false
and call
refreshCache()
manually at a cadence that works for you - this gives you full control over when network requests happen
b
Thankyou @powerful-spoon-16837, this helps. Our reading of the Swift SDK documentation here and here suggested to us that to-disk caching happened automatically unless we had a custom location to cache. Good to know that isnt the case, thankyou
One more question @powerful-spoon-16837: If we did as you suggested and cached the feature data ourselves and provide it to new connections. What happens in the following scenario: • Open a client and fetch the feature state • Cache the feature state • close the client • .... time passes ..... • features get updated in the growthbook console • .... time passes.... • Open a new client with background sync, passing the feature state Does the new client detect the changes that have happened since the provided feature state version, or will it miss the updated changes?
p
If you provide features during initialization, the SDK won't make the initial feature fetch - it will work with the features you provided directly. The main reason why a GET request happens before the SSE connection is established is that when you establish SSE, the server does not send the current feature state on connect - it only sends events when something changes. That's why the SDK was designed with an initial fetch first and then SSE, so the client always has up-to-date feature data at startup. So: You initialize the SDK with a preloaded feature. The SDK caches it and works with it immediately. If you don't call
refreshCache()
or enable
backgroundSync
, the SDK will keep working with that preloaded data. 1. If you call
refreshCache()
or SSE sends new data, the SDK will update and cache the new features. 2. If you close the client, the SSE connection is also closed. No updates will be received while the client is closed - the SDK persists whatever was cached before closing. 3. When you initialize again, there are two options: a. With preloaded features - the SDK uses them immediately without a network request. But any changes that happened while the client was closed will be missed until the next change occurs in the console. To avoid this, call
refreshCache()
after init. 4. Without preloaded features - the SDK always makes a GET request to fetch the current state from the server, so you're guaranteed to have up-to-date features.
b
Thankyou @powerful-spoon-16837 that was what I was afraid of. It makes sense, but also makes caching the feature state untenable for us. In the scenario I outlined above, if the app is backgrounded while a console update happens, the app will not get the update until the next time an update occurs, and then ONLY IF, the app is in the foreground when that update occurs The way that COULD work is if the app could subscribe to notifications from the last place in the notification queue that it saw. ie: I last saw version 3, please tell me about any updates from that point on, and the server responds immediately with "we're currently at version 5, do a refresh"