Skip to content

Fix: Clear in-memory offerings cache on locale override to prevent stale paywall data#3225

Merged
ajpallares merged 3 commits into
mainfrom
pallares/improve-preferred-locale
Mar 12, 2026
Merged

Fix: Clear in-memory offerings cache on locale override to prevent stale paywall data#3225
ajpallares merged 3 commits into
mainfrom
pallares/improve-preferred-locale

Conversation

@ajpallares

@ajpallares ajpallares commented Mar 12, 2026

Copy link
Copy Markdown
Member

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-ios and hybrids

Motivation

overridePreferredUILocale() sets the locale synchronously and triggers an offerings re-fetch in the background, but does not clear the in-memory offerings cache. When a paywall is presented immediately after, the stale-while-revalidate path returns the cached offerings (fetched with the old locale's X-Preferred-Locales header) and the paywall renders the wrong language. On the second presentation the cache is fresh and the correct locale appears.

iOS counterpart: RevenueCat/purchases-ios#6446

Description

When overridePreferredUILocale is called and the rate limiter allows, we now clear the in-memory offerings cache before re-fetching offerings. This ensures that any subsequent offerings() call (e.g., from a paywall) finds no cached data and waits for the fresh network response with the correct locale header, rather than returning stale data.

  • Added clearInMemoryOfferingsCache() to OfferingsCache and OfferingsManager — clears the in-memory offerings instance and locale tags, but preserves the disk cache as a network-error fallback.
  • Renamed fetchOfferingsWithRateLimit to clearCacheAndFetchOfferingsWithRateLimit — both the cache clear and the re-fetch are gated by the rate limiter so neither happens when rate-limited.
  • Removed fetchCurrent = true from the offerings fetch since the in-memory cache is already cleared beforehand.

This is purely an internal behavior change with no public API impact.


Note

Medium Risk
Changes offerings caching behavior during locale overrides by clearing in-memory state and altering fetch semantics; could affect when/which cached offerings are returned, but is scoped and covered by new unit tests.

Overview
Fixes stale paywall language after overridePreferredUILocale() by clearing the in-memory Offerings cache before refetching, ensuring subsequent getOfferings() calls don’t immediately vend offerings fetched under the previous locale.

Adds clearInMemoryOfferingsCache() to OfferingsCache/OfferingsManager (clears in-memory offerings + cached locale tags while preserving disk cache for fallback), and updates the locale-override rate-limited refresh path to gate both the cache clear and fetch; tests were added to cover ordering, unchanged-locale behavior, rate limiting, and failure cases.

Written by Cursor Bugbot for commit 914cbd7. This will update automatically on new commits. Configure here.

…aywall data

When `overridePreferredUILocale` is called, the cached offerings may contain
localized data for the old locale. Without clearing the cache, a subsequently
presented paywall could render stale data via the stale-while-revalidate path.

The fix clears the in-memory offerings cache and re-fetches, both gated behind
the existing rate limiter. The disk cache is preserved as a fallback for
network errors.

Made-with: Cursor
@ajpallares ajpallares marked this pull request as ready for review March 12, 2026 11:42
@ajpallares ajpallares requested a review from a team as a code owner March 12, 2026 11:42

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thanks!

@ajpallares ajpallares enabled auto-merge March 12, 2026 11:52
@ajpallares ajpallares added this pull request to the merge queue Mar 12, 2026
@codecov

codecov Bot commented Mar 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.34%. Comparing base (449c51b) to head (914cbd7).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3225      +/-   ##
==========================================
+ Coverage   79.18%   79.34%   +0.15%     
==========================================
  Files         356      356              
  Lines       14273    14276       +3     
  Branches     1945     1945              
==========================================
+ Hits        11302    11327      +25     
+ Misses       2166     2144      -22     
  Partials      805      805              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Merged via the queue into main with commit 4ad4755 Mar 12, 2026
30 checks passed
@ajpallares ajpallares deleted the pallares/improve-preferred-locale branch March 12, 2026 12:21
github-merge-queue Bot pushed a commit that referenced this pull request Mar 16, 2026
**This is an automatic release.**

## RevenueCat SDK
### 🐞 Bugfixes
* Fix & Standardize Galaxy Date Parsing Edge Cases (#3216) via Will
Taylor (@fire-at-will)
* Fix addSuccessfullyPostedToken for new purchases in
PostPendingTransactionsHelper (#3239) via Facundo Menzella
(@facumenzella)
* [Galaxy]: Fix race condition when fetching Galaxy products (#3213) via
Will Taylor (@fire-at-will)
* Fixes double padding in PaywallActivity on Android 15+ when
`edgeToEdge` parameter is false (#3227) via Cesar de la Vega (@vegaro)

## RevenueCatUI SDK
### 🐞 Bugfixes
* Fix bold text not rendering in Markdown lists (#3228) via Cesar de la
Vega (@vegaro)
* Fix: Clear in-memory offerings cache on locale override to prevent
stale paywall data (#3225) via Antonio Pallares (@ajpallares)
### Paywallv2
#### ✨ New Features
* Feature: Update default paywall (#3133) via Jacob Rakidzich
(@JZDesign)
#### 🐞 Bugfixes
* Fix V2 paywall safe area in landscape mode (#3221) via Cesar de la
Vega (@vegaro)

### 🔄 Other Changes
* Run integration tests on all branches (#3242) via Toni Rico
(@tonidero)
* Migrate Firebase Test Lab jobs to CircleCI emulators (#3238) via Toni
Rico (@tonidero)
* Run metalava on galaxy module in test-galaxy job (#3235) via Will
Taylor (@fire-at-will)
* Add offering_id to custom paywall impression event (#3230) via Rick
(@rickvdl)
* Cache isAutoRenewing to detect subscription changes without
syncPurchases (#3198) via Facundo Menzella (@facumenzella)
* Bump fastlane-plugin-revenuecat_internal from `e146447` to `3e8c384`
(#3233) via dependabot[bot] (@dependabot[bot])

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk release housekeeping: version string bumps and
documentation/deployment path updates with no functional runtime logic
changes beyond the exposed version constant.
> 
> **Overview**
> Publishes the `9.26.0` release by removing `-SNAPSHOT` across
build/version metadata (root `VERSION_NAME`, `.version`,
`Config.frameworkVersion`, and sample/test app dependency pins).
> 
> Updates release documentation artifacts by adding the `9.26.0` notes
to `CHANGELOG.md`/`CHANGELOG.latest.md`, switching docs deployment in
CircleCI to sync `docs/9.26.0` to S3, and updating `docs/index.html` to
redirect to the new version.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0a30a45. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants