# AI paywall screen

> A paywall for AI apps with weekly and yearly plans that each carry a credit allowance. The billed amount is always the largest price, weekly math stays in small text, the auto-renew line sits next to the buy button, and Terms, Privacy and Restore are always shown. check-kit fails if a price variant breaks this.

- Type: Component (screens)
- Access: Pro
- Page: https://goodui.dev/native/components/ai-paywall-screen
- Markdown: https://goodui.dev/native/components/ai-paywall-screen.md
- Registry item: https://goodui.dev/native/r/ai-paywall-screen.json
- Dependencies: react-native-reanimated
- Keywords: react native ai paywall, credits subscription, weekly yearly plans, revenuecat paywall ui, in app purchase credits, free trial paywall

## When to use

- Selling a subscription where each generation has a real cost, so a plan grants credits.
- Right after a first result, with that result in the hero slot.

## When not to use

- Monthly and yearly plans without credits: use paywall-screen.
- One-off credit packs: this screen sells subscriptions only.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add @goodui-native-pro/ai-paywall-screen
npx expo install --fix
```

Pro: add `"@goodui-native-pro": { "url": "https://goodui.dev/native/r/pro/{name}.json", "headers": { "Authorization": "Bearer ${GOODUI_LICENSE_KEY}" } }` to the `registries` of components.json and put your license key in .env.local.

The component lands in `components/goodui-native/ai-paywall-screen/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs button, credits-meter, locale.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
// app/paywall.tsx (presented as a modal route)
import { Image, Linking } from "react-native";
import { router } from "expo-router";
import { AiPaywallScreen } from "@/components/goodui-native/ai-paywall-screen/ai-paywall-screen";

export default function Paywall() {
  return (
    <AiPaywallScreen
      title="Keep creating"
      subtitle="Your first portrait is ready. Plans include credits for every render."
      benefits={["HD exports", "No watermark", "Every style"]}
      defaultPlanId="year"
      hero={<Image source={result} style={{ width: "100%", height: "100%" }} accessibilityIgnoresInvertColors />}
      plans={[
        { id: "year", period: "year", name: "Yearly", price: 59.99, credits: 2400, savePercent: 62 },
        { id: "week", period: "week", name: "Weekly", price: 5.99, credits: 40, trialDays: 3 },
      ]}
      onClose={() => router.back()}
      onRestore={() => restorePurchases()}
      onTerms={() => Linking.openURL(TERMS_URL)}
      onPrivacy={() => Linking.openURL(PRIVACY_URL)}
      onSubscribe={(planId) => purchase(planId)}
    />
  );
}
```

## API reference

### AiPaywallScreen

`import { AiPaywallScreen } from "@/components/goodui-native/ai-paywall-screen/ai-paywall-screen";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` (required) | `string` | – | – |
| `subtitle` | `string` | – | – |
| `benefits` (required) | `string[]` | – | What the person gets, in order of pull. Keep to three or four lines. |
| `plans` (required) | `AiPlan[]` | – | – |
| `defaultPlanId` | `string` | – | Plan selected at open. |
| `currency` | `string` | `"USD"` | ISO currency code. |
| `hero` | `ReactNode` | – | Art behind the title: a result the person just made is the strongest choice. |
| `closeDelay` | `number` | `1.5` | Seconds before the close button appears. 0 shows it at once. Stores require a way out either way. |
| `onClose` (required) | `() => void` | – | – |
| `onSubscribe` (required) | `(planId: string) => unknown` | – | Return a promise: the buy button shows loading until it settles, and an error state if it rejects. |
| `onRestore` (required) | `() => unknown` | – | Required by the stores, so always shown. |
| `onTerms` (required) | `() => void` | – | Opens your terms of use. Always shown. |
| `onPrivacy` (required) | `() => void` | – | Opens your privacy policy. Always shown. |
| `onNotNow` | `() => void` | – | Shows a quiet Not now link. Leave the paywall from here; do not open a second offer. |
| `labels` | `Partial<AiPaywallLabels>` | – | – |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## Accessibility

- The title is a header and the plans are a radio group; each radio reads its name, price and credits.
- Close and Restore are labeled buttons; Terms and Privacy are links. All have touch targets larger than their text.

## Motion

- Text and benefits rise in with a short stagger, the selected plan's dot springs in, and the buy button breathes slowly.
- The close button fades in after closeDelay seconds.
- Reduced motion: content fades in and the buy button holds still.

## Haptics

- Choosing a plan uses the select cue; the buy button uses confirm.

## Performance

- The breathing buy button is one transform on the UI thread.

## Notes for AI

- Pass the store's localized string in `priceLabel`. `price` stays a number for the weekly math.
- Do not add prices outside planPricing or restyle them: Apple requires the billed amount to be the most conspicuous pricing element, and scripts/check-paywall.ts enforces it.
- Return a promise from onSubscribe so the button shows loading and errors.
- savePercent is a number you state: compute it from your real prices.
- onRestore, onTerms and onPrivacy are required: point them at real pages before you ship.
- Keep closeDelay short. Stores require a way out.
- The screen does not grant credits: call credits.renew in onSubscribe after the purchase succeeds.
- onNotNow shows a quiet Not now link. Use it to leave the paywall, never to open a second offer.

## Related

- [Paywall screen](https://goodui.dev/native/components/paywall-screen.md): A complete subscription paywall: a monthly and yearly toggle with a savings badge, plan cards whose prices roll digit by digit when the period changes, a feature list, a trial note that always states the price, restore purchases and an async subscribe button.
- [Credits meter](https://goodui.dev/native/components/credits-meter.md): A balance pill for an app bar whose digits roll when the balance changes and which turns warning colored when low, plus CreditsCost, a live price line that says what a job costs and what is left after it.
- [AI consent screen](https://goodui.dev/native/components/ai-consent-screen.md): A consent screen shown before personal data reaches a third-party AI service: it names the provider, lists what is sent and what is not, has an optional age tick, and offers a visible way to decline.
- [Rolling number](https://goodui.dev/native/components/rolling-number.md): A number whose digits roll in the direction of change, with digits that open and close in place and currency signs that glide instead of jumping.

## Guidance for AI tools

AI paywall screen: A paywall for AI apps with weekly and yearly plans that each carry a credit allowance. The billed amount is always the largest price, weekly math stays in small text, the auto-renew line sits next to the buy button, and Terms, Privacy and Restore are always shown. check-kit fails if a price variant breaks this. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
