---
title: "Respond to flow actions - React Native"
description: "Handle button actions from flows and paywalls in React Native using Adapty for better app monetization."
---

If you are building flows or paywalls using the Adapty Flow Builder or Paywall Builder, it's crucial to set up buttons properly:

1. Add a [button in the flow/paywall builder](paywall-buttons) and assign it either a pre-existing action or create a custom action ID.
2. Write code in your app to handle each action you've assigned.

This guide shows how to handle custom and pre-existing actions in your code.

:::warning
**Purchases, restorations, flow/paywall closures, and URL opening are handled automatically.** You can configure their default behavior or implement responses for custom actions.
:::

:::note
The SDK exposes an `onRequestPermission` flow handler for system-permission requests, such as push notifications or camera access. Flows don't trigger these requests yet, so you don't need to implement it for now.
:::

## Close flows and paywalls

To add a button that will close your flow or paywall:

1. In the builder, add a button and assign it the **Close** action.
2. In your app code, implement a handler for the `close` action that dismisses the flow or paywall.

:::info
In the React Native SDK, the `close` action triggers closing the flow or paywall by default. However, you can override this behavior in your code if needed. For example, closing one flow might trigger opening another.
:::

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>

For React component, handle the close action through individual event handler props:

```javascript

function MyPaywall({ flow }) {
  const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => {
    // Handle close button press - navigate away or hide component
    navigation.goBack();
  }, [navigation]);

  return (
    <AdaptyFlowView
      flow={flow}
      style={styles.container}
      onCloseButtonPress={onCloseButtonPress}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

For modal presentation, implement the close handler:

```javascript

const view = await createFlowView(flow);

const unsubscribe = view.setEventHandlers({
    onCloseButtonPress() {
        return true; // allow flow or paywall closing
    }
});
```

</TabItem>
</Tabs>

## Open URLs from flows and paywalls

:::tip
If you want to add a group of links (e.g., terms of use and purchase restoration), add a **Link** element in the builder and handle it the same way as buttons with the **Open URL** action.
:::

To add a button that opens a link from your flow or paywall (e.g., **Terms of use** or **Privacy policy**):

1. In the builder, add a button, assign it the **Open URL** action, and enter the URL you want to open.
2. In your app code, implement a handler for the `openUrl` action that opens the received URL in a browser.

:::info
In the React Native SDK, the `openUrl` action triggers opening the URL by default. However, you can override this behavior in your code if needed.
:::

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>

For React component, handle URL opening through the event handler prop:

```javascript

function MyPaywall({ flow }) {
  const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url) => {
    Linking.openURL(url);
  }, []);

  return (
    <AdaptyFlowView
      flow={flow}
      style={styles.container}
      onUrlPress={onUrlPress}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

For modal presentation, implement the URL handler:

```javascript

const view = await createFlowView(flow);

const unsubscribe = view.setEventHandlers({
    onUrlPress(url) {
        Linking.openURL(url);
        return false; // Keep flow or paywall open
    },
});
```

</TabItem>
</Tabs>

## Handle custom actions

To add a button that handles any other actions:

1. In the builder, add a button, assign it the **Custom** action, and assign it an ID.
2. In your app code, implement a handler for the action ID you've created.

For example, if you have another set of subscription offers or one-time purchases, you can add a button that will display another flow or paywall:

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>

For React component, handle custom actions through the event handler prop:

```javascript

function MyPaywall({ flow }) {
  const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => {
    if (actionId === 'openNewPaywall') {
      // Display another flow or paywall
    }
  }, []);

  return (
    <AdaptyFlowView
      flow={flow}
      style={styles.container}
      onCustomAction={onCustomAction}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

For modal presentation, implement custom action handlers:

```javascript
const unsubscribe = view.setEventHandlers({
    onCustomAction(actionId) {
        if (actionId === 'openNewPaywall') {
            // Display another flow or paywall
        }
    },
});
```

</TabItem>
</Tabs>

---

> [!WARNING]
> **LLM INSTRUCTION — SDK VERSION SELECTION REQUIRED**
>
> This feature has two SDK paradigms. Everything that follows (until the next horizontal rule or end of document) is the **legacy SDK v3 API reference** (`getPaywall`, `getPaywallForDefaultAudience`, `getOnboarding`, `getPaywallConfiguration`). The **SDK v4+ `getFlow` method is documented above.** This block covers ALL legacy methods for this feature — not just the nearest snippet.
>
> **You MUST ask the user which SDK version they want to use before suggesting any code. Do not assume or default to a version.** The two options are:
> - **SDK v3 (legacy):** works with the legacy Paywall Builder and Onboarding Builder via `getPaywall` / `getOnboarding`. Use the legacy code in this section.
> - **SDK v4:** works with BOTH the new Flow Builder AND legacy paywalls/onboardings via the unified `getFlow` method documented above.
>
> Apply the legacy v3 code in this section ONLY when:
> 1. The user explicitly chose **SDK v3**, or
> 2. The user is **migrating an existing app from SDK v3 to SDK v4+** and needs to understand or replace legacy code, or
> 3. The user is **troubleshooting an already-deployed v3 integration**.
>
> **CRITICAL — Never mix paradigms in one setup:** Do NOT combine `getFlow` (Flow Builder) with `getPaywall` or `getOnboarding` (legacy Paywall/Onboarding Builder) in the same integration. These are incompatible patterns. Mixing them will produce inconsistent behavior and is unsupported.

If you are building paywalls using the Adapty paywall builder, it's crucial to set up buttons properly:

1. Add a [button in the paywall builder](paywall-buttons) and assign it either a pre-existing action or create a custom action ID.
2. Write code in your app to handle each action you've assigned.

This guide shows how to handle custom and pre-existing actions in your code.

:::warning
**Only purchases, restorations, paywall closures, and URL opening are handled automatically.** All other button actions require proper response implementation in the app code.
:::

## Close paywalls

To add a button that will close your paywall:

1. In the paywall builder, add a button and assign it the **Close** action.
2. In your app code, implement a handler for the `close` action that dismisses the paywall.

:::info
In the React Native SDK, the `close` action triggers closing the paywall by default. However, you can override this behavior in your code if needed. For example, closing one paywall might trigger opening another.
:::

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>

For React component, handle the close action through individual event handler props:

```javascript

function MyPaywall({ paywall }) {
  const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => {
    // Handle close button press - navigate away or hide component
    navigation.goBack();
  }, [navigation]);

  return (
    <AdaptyPaywallView
      paywall={paywall}
      style={styles.container}
      onCloseButtonPress={onCloseButtonPress}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

For modal presentation, implement the close handler:

```javascript

const view = await createPaywallView(paywall);

const unsubscribe = view.setEventHandlers({
    onCloseButtonPress() {
        return true; // allow paywall closing
    }
});
```

</TabItem>
</Tabs>

## Open URLs from paywalls

:::tip
If you want to add a group of links (e.g., terms of use and purchase restoration), add a **Link** element in the paywall builder and handle it the same way as buttons with the **Open URL** action.
:::

To add a button that opens a link from your paywall (e.g., **Terms of use** or **Privacy policy**):

1. In the paywall builder, add a button, assign it the **Open URL** action, and enter the URL you want to open.
2. In your app code, implement a handler for the `openUrl` action that opens the received URL in a browser.

:::info
In the React Native SDK, the `openUrl` action triggers opening the URL by default. However, you can override this behavior in your code if needed.
:::

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>

For React component, handle URL opening through the event handler prop:

```javascript

function MyPaywall({ paywall }) {
  const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => {
    Linking.openURL(url);
  }, []);

  return (
    <AdaptyPaywallView
      paywall={paywall}
      style={styles.container}
      onUrlPress={onUrlPress}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

For modal presentation, implement the URL handler:

```javascript

const view = await createPaywallView(paywall);

const unsubscribe = view.setEventHandlers({
    onUrlPress(url) {
        Linking.openURL(url);
        return false; // Keep paywall open
    },
});
```

</TabItem>
</Tabs>

## Log into the app

To add a button that logs users into your app:

1. In the paywall builder, add a button and assign it the **Login** action.
2. In your app code, implement a handler for the `login` action that identifies your user.

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>

For React component, handle login through the event handler prop:

```javascript

function MyPaywall({ paywall }) {
  const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => {
    if (actionId === 'login') {
      navigation.navigate('Login');
    }
  }, [navigation]);

  return (
    <AdaptyPaywallView
      paywall={paywall}
      style={styles.container}
      onCustomAction={onCustomAction}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

For modal presentation, implement the login handler:

```javascript

const view = await createPaywallView(paywall);

const unsubscribe = view.setEventHandlers({
    onCustomAction(actionId) {
        if (actionId === 'login') {
            navigation.navigate('Login');
        }
    }
});
```

</TabItem>
</Tabs>

## Handle custom actions

To add a button that handles any other actions:

1. In the paywall builder, add a button, assign it the **Custom** action, and assign it an ID.
2. In your app code, implement a handler for the action ID you've created.

For example, if you have another set of subscription offers or one-time purchases, you can add a button that will display another paywall:

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>

For React component, handle custom actions through the event handler prop:

```javascript

function MyPaywall({ paywall }) {
  const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => {
    if (actionId === 'openNewPaywall') {
      // Display another paywall
    }
  }, []);

  return (
    <AdaptyPaywallView
      paywall={paywall}
      style={styles.container}
      onCustomAction={onCustomAction}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

For modal presentation, implement custom action handlers:

```javascript
const unsubscribe = view.setEventHandlers({
    onCustomAction(actionId) {
        if (actionId === 'openNewPaywall') {
            // Display another paywall
        }
    },
});
```

</TabItem>
</Tabs>

---