# Local Testing with a .storekit File

Local testing runs OnsideKit fully offline against a bundled **`.storekit`** configuration file. Products come from the file, login is automatic and fake, and purchases and restores run against a local simulation — no backend, no registered app, and no real Onside account.

## Enable it

1. Add a StoreKit configuration file to your app target — for example `LocalProducts.storekit`. (Xcode can create one via **File → New → File → StoreKit Configuration File**.)
2. Pass its **base name** (no extension) to `initialize`:

```swift
Onside.initialize(storeKitConfigurationName: "LocalProducts")
```

When `storeKitConfigurationName` is `nil` (the default), the SDK runs normally against the live backend. The choice is fixed at the first `initialize` call.

On success the SDK logs:

```
[Onside]: ✅ Initialized for local testing with N product(s) from LocalProducts.storekit
```

## How it behaves

* **Products** come from the `.storekit` file. [`makeProductsRequest`](/sdk/products-and-subscriptions/fetching-products.md) returns the configured products, matched by identifier.
* **Login is automatic and offline** — the SDK commits a synthetic session with no phone verification or store-app handoff. `requestLogin` "succeeds" instantly, and the storefront country is the one you set in the file (see `_storefront` below). `logout()` still clears it.
* **Purchases** present a fake Apple-Pay-style sheet (no real charge) and complete the transaction through the normal [payment queue](/sdk/core-concepts/payment-queue.md). Restorable products (non-consumables and subscriptions) are remembered locally; re-buying one shows an "already purchased" alert.
* **Restore** replays the locally remembered purchases.

{% hint style="info" %}
The standard OnsideKit APIs are unchanged — the same queue, observers, and transaction flow. This is the recommended way to exercise the purchase UI, including the [storefront/price-change gate](/sdk/purchasing/storefront-price-changes.md), without a backend.
{% endhint %}

### Not supported in local testing

Two APIs require a real account and return a dedicated error:

* `Onside.presentPaymentMethodsManager(completion:)` → `.notSupportedInLocalTesting`
* `Onside.makeSignedInAppsHistoryRequest()` → `.notSupportedInLocalTesting`

## Reset between runs

```swift
Onside.resetLocalTestingState()
```

This clears the locally remembered purchase history so you can simulate a fresh install — restorable products are forgotten and re-buying one shows the full payment sheet again. It does not clear the fake login or the parsed products.

## The .storekit file

OnsideKit reads a subset of Apple's StoreKit configuration format.

```json
{
  "products": [
    {
      "productID": "remove_ads",
      "referenceName": "Remove Ads",
      "type": "NonConsumable",
      "displayPrice": "4.99",
      "localizations": [
        { "locale": "en_US", "displayName": "Remove Ads", "description": "Removes all ads." }
      ]
    }
  ],
  "subscriptionGroups": [
    {
      "id": "21F5C0E3",
      "name": "Premium",
      "localizations": [
        { "locale": "en_US", "displayName": "Premium", "description": "" }
      ],
      "subscriptions": [
        {
          "productID": "subscription_monthly",
          "referenceName": "Premium Monthly",
          "type": "RecurringSubscription",
          "displayPrice": "9.99",
          "recurringSubscriptionPeriod": "P1M",
          "localizations": [
            { "locale": "en_US", "displayName": "Premium Monthly", "description": "Monthly premium." }
          ]
        }
      ]
    }
  ],
  "settings": {
    "_locale": "en_US",
    "_storefront": "US"
  }
}
```

**Supported fields**

* `products[]`: `productID`, `referenceName`, `type` (`Consumable` → consumable; anything else → non-consumable), `displayPrice`, `localizations[]`.
* `subscriptionGroups[]`: `id`, `name`, `localizations[]`, `subscriptions[]`.
* `subscriptions[]`: `productID`, `referenceName`, `type`, `displayPrice`, `recurringSubscriptionPeriod` (ISO-8601 duration, e.g. `P1M`), `localizations[]`.
* `localizations[]`: `locale`, `displayName`, `description`.
* `settings`: `_locale` (preferred localization, default `en_US`) and `_storefront` (the testing storefront/country code — set this explicitly).

{% hint style="warning" %}
In local testing, all prices render in **EUR** — only the numeric value comes from `displayPrice`. Set `_storefront` to the ISO country code you want to test; the storefront country drives region-dependent behavior.
{% endhint %}


---

# Agent Instructions: 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:

```
GET https://docs.onside.io/sdk/advanced-and-tooling/local-testing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
