# Local Resources

Bundle images, videos, and other assets in your app so paywalls can load them instantly from the device.

Local resources let your paywalls load bundled assets directly from the device instead of fetching them over the network. This is useful for hero images, onboarding videos, and other media that should appear immediately even when the connection is slow.

:::expo
> **Info**

Local resources require &#x2A;*Expo SDK v1.1.3+**.


:::

Registering local resources [#registering-local-resources]

Choose a stable resource ID for each asset you want to serve locally. That same ID is what you'll select in the [paywall editor](/docs/dashboard/dashboard-creating-paywalls/paywall-editor-local-resources) when configuring image or video components.

:::expo
On Expo, pass `localResources` in the `options` prop on `SuperwallProvider`. Entries are resolved during configuration — Metro `require()` results are downloaded via `expo-asset` so the webview can read them from a `file://` URI.

```tsx Expo
import * as FileSystem from "expo-file-system"
import { SuperwallProvider } from "expo-superwall"

export function App() {
  return (
    <SuperwallProvider
      apiKeys={{ ios: "pk_your_ios_api_key", android: "pk_your_android_api_key" }}
      options={{
        localResources: {
          "hero-image": require("./assets/hero.png"),
          "logo": { uri: FileSystem.documentDirectory + "logo.png" },
          "onboarding-video": "file:///path/to/welcome.mp4",
        },
      }}
    >
      {/* your app */}
    </SuperwallProvider>
  )
}
```

> **Warning**

`localResources` is resolved when `SuperwallProvider` configures the SDK. Resources added later
will not be available to paywalls that already loaded.


:::

Supported source types [#supported-source-types]

:::expo
Each entry in `localResources` accepts one of:

| Type                         | Use for                                                            |
| ---------------------------- | ------------------------------------------------------------------ |
| `number` (Metro `require()`) | Bundled assets in your Expo project; resolved through `expo-asset` |
| `string`                     | A `file://`, `content://`, or absolute path URI                    |
| `{ uri: string }`            | The same shape used by React Native `Image` sources                |
:::

Choosing resource IDs [#choosing-resource-ids]

Resource IDs are the contract between your app and the paywall editor. A few guidelines:

* Use stable, descriptive names like `"hero-image"` and `"onboarding-video"`.
* Keep the casing consistent. `"Hero-Image"` and `"hero-image"` are different IDs.
* If you rename an ID, update any paywalls that reference it.

Referencing local resources in a paywall [#referencing-local-resources-in-a-paywall]

In the paywall editor, set a local resource on an image or video component and select the resource ID you registered in the SDK. You can still provide a remote URL as a fallback.

Under the hood, paywalls load these resources through `swlocal://` URLs. For example:

```html
<video src="swlocal://onboarding-video" autoplay muted playsinline></video>
```

If the SDK cannot resolve a local resource, the paywall can fall back to the remote URL configured in the editor.

Debugging [#debugging]

If a resource ID does not appear in the editor or fails to load:

* Make sure the app is running a compatible SDK version.
* Confirm the resource ID in your paywall exactly matches the key you registered in the SDK.
* Open a paywall on a test device after configuring local resources so the editor can discover recently used IDs.
* Keep a remote fallback URL on critical media so older builds still render correctly.

Related [#related]

:::expo
* [Configuring the SDK](/docs/expo/guides/configuring): Where `localResources` lives in the Expo options surface.
:::

* [Paywall Editor: Local Resources](/docs/dashboard/dashboard-creating-paywalls/paywall-editor-local-resources): How to assign local resource IDs in the dashboard.