# How to build a Fitness app with Bravo, Xano and RevenueCat

<figure><img src="/files/yHB9puXEOJ9VSQf11TxA" alt=""><figcaption></figcaption></figure>

In this tutorial we are going to explain how to build a Fitness app with Bravo Studio, Figma, Xano and RevenueCat. The app will allow users to explore workout videos and food recipes as well as subscribe to premium content.

Some of the features of this app are:

* [Custom login with Xano](#set-up-custom-login-with-xano)
* [Like button](/bravo-tags/components/stateful-component-like-button.md)
* [Map](/bravo-tags/map-with-markers.md)
* [In-app purchase](#set-up-in-app-purchase)

{% embed url="<https://www.youtube.com/watch?v=7eSzOy74iVM>" %}

## Requirements

* [Figma account](https://www.figma.com/) (free)
* [Xano account](https://app.xano.com/admin/signup/bravostudio) (free)
* Bravo Solo plan + Business app (218€/month)
* [RevenueCat account](https://www.revenuecat.com/) (free)
* [Apple developer account](https://developer.apple.com/) (99€/year)
* Some knowledge about APIs and database relationships

## The design

<figure><img src="/files/XmVp6s3sZNQx3R44kcYN" alt=""><figcaption></figcaption></figure>

First of all let’s have a look at the design: [Bravo Use Case: Fitness app](https://www.figma.com/community/file/1217435722039388173)

You can see the design is fully bravorized with containers and Bravo tags, the navigation is set up and the layers that will be bound to real data contain an asterisk (a little trick we do to speed up binding process later). Feel free to explore the design and learn how it’s been built.

For example, check out the Paywall screen. The CTA layer contains the tag <mark style="color:red;">`[action:purchase:full]`</mark> which allows the user to trigger the purchase action of the “full” subscription. Inside it, we have a text layer with <mark style="color:red;">`[price:full]`</mark> and <mark style="color:red;">`{price}`</mark> within the text, which shows the app user the corresponding price of the subscription.

Let’s duplicate the design and make it of your own.

<figure><img src="/files/Ol1Q0Rcy9gMH9sllzZQ0" alt=""><figcaption></figcaption></figure>

1. In Figma, [duplicate this design file](https://www.figma.com/community/file/1217435722039388173) to your account
2. In your duplicated file, click `Share`, then `Copy link`. Make sure the permission for "Anyone with the link" is `can view`.
3. In Bravo Studio, go to [Create a new app](https://projects.bravostudio.app/apps/new)
4. Paste the link from step 2 into the input field. Click `Connect Bravorized Figma file`
5. Once the app is successfully created you will see the app screens imported from your design.

{% hint style="info" %}
Make sure your account plan is Olé and you have upgraded to Business app in order to follow the tutorial successfully.
{% endhint %}

## The backend

For the database and API we are using Xano, one of the best no-code tools that you can connect to Bravo and launch a complete backend in minutes.

{% hint style="info" %}
Bravo users enjoy a **10% discount on any Xano package** if you sign up from our referral url -> <https://app.xano.com/admin/signup/bravostudio>
{% endhint %}

One of the coolest features of Xano are snippets. Snippets allow you to clone a complete backend to your own account with just a click, including database entities, data records and API endpoints. We have a complete backend already set up for this tutorial! Awesome, right?

1. Open this snippet.
2. Click on “**Add to your Xano account**”.
3. Login and add it to your Xano instance.
4. From your Workspace, open the Marketplace tab and select the Purchased section.
5. Once selected, you can review the Snippet and click to install it to your Workspace.
6. If you have any trouble, check out the full docs on [how to add a snippet](https://docs.xano.com/xano-features/snippets/preview-and-add-a-snippet).

<figure><img src="/files/kXYtVCAXoEnKd6GvIHBB" alt=""><figcaption></figcaption></figure>

The database consists of six tables:

* Fitness\_workout
* Fitness\_workout\_category
* Fitness\_user
* Fitness\_user\_recipe
* Fitness\_recipe
* Fitness\_spot

These tables already contain data records for your convenience. For example, *Fitness\_workout* contains the list of workouts with title, description, video url and other fields. This table is connected to *Firtness\_workout\_category* by *category\_id*. Feel free to checkout the rest of tables and how they relate to each other.

{% hint style="info" %}
If you are not familiar with database relationships, you can learn the basics with [this tutorial from Xano](https://docs.xano.com/database/database-relationships).
{% endhint %}

Now let’s take a look to the API endpoints.

1. Open the **API** tab from the left menu
2. Click on **Fitness Use Case**

You will see a bunch of API endpoints grouped by name. Some of them include custom filters and rules. For example, open */fitness\_workout\_featured.* The endpoint queries all workouts where *isFeatured* is true and *isPremium* is false.

Please note that authentication is required for all endpoints (except */auth/signup* and */auth/login*), which means that the request must include the auth token in the headers for it to run successfully. We'll go over this later, but for now this will give you a sense of the power of Xano 🔥.

## Set up custom login with Xano

Now that we have our design connected to our Bravo app and the backend is ready, we can proceed with connecting both by configuring app authentication.

Bravo Studio supports different methods for authenticate users into your app: OAuth 2.0, Firebase login and Custom Authentication. The latter is the method we will use to configure Xano.

<figure><img src="/files/ec5Jo9xxrZE7zo7HcMBs" alt=""><figcaption></figcaption></figure>

Since our Xano Snippet already has the necessary endpoints, we’ll go to Bravo and connect them to our app. If you want to set it up from scratch, learn [how to set up Xano as your user authentication backend](https://docs.bravostudio.app/integrations/user-authentication/authentication-with-custom-backend/set-up-xano-as-your-user-authentication-backend).

1. In Bravo, go to **API Collections → Create a new collection**
2. Select **Xano Wizard**
3. [Go to your account](https://app.xano.com/admin/account) in Xano and copy **Your Private Developer API Key**
4. Go back to Bravo and **paste the API Key** in the input field
5. Click **Continue**
6. Select the **instance** that contains the cloned snippet and **Continue**
7. Select the **Fitness Use Case** API group and **Continue**
8. Now you’ll see the list of endpoints. Click **Select all** and **Continue**

🎉 Congrats! You have imported the API endpoints to Bravo.

Now we’ll need to do some important tweaks to finalise the set up.

1. Select the request named **Auth · Login**
2. Select **Test Values** tab
3. For **email**, set **<test@test.com>** as value
4. For **password**, set **12345678**
5. Press **Send**
6. Go to **Selected Data** tab and change the **Variable Name** from “authtoken” to **accessToken**
7. Go to **Received Data** tab and copy the value of the token (a long string usually starting by “ey”)
8. Click on to the **wheel icon** nearby the API Collection name

<figure><img src="/files/bYIoybUHrPEA47ilqTEA" alt=""><figcaption></figcaption></figure>

9. Go to **Authentication** tab and select **Bearer**
10. Paste the copied token in the **Token** field and click **Save**

Now all of the requests sent on this screen are authenticated. If in the future the auth token expires, you’ll need to repeat the steps 5 to 10.

## Auth tags

<figure><img src="/files/dON5P98E7gWpArRiHWL9" alt=""><figcaption></figcaption></figure>

Let’s review how the login screen is *bravorized*. First of all, it has a <mark style="color:red;">`[page:login]`</mark> tag in the top-level frame and a <mark style="color:red;">`[post-login:action]`</mark> tag that we’ll cover later.

We also have two textfields with form tags: <mark style="color:red;">`[component:input-email]`</mark> and <mark style="color:red;">`[component:input-password]`</mark>. To submit the form we have a [stateful component](https://docs.bravostudio.app/bravo-tags/interactive-component/stateful-component-like-button) with two states: *default* and *pressed*. The first has the submit action for login forms: <mark style="color:red;">`[action:login]`</mark>. Learn more about [forms and input fields](https://docs.bravostudio.app/bravo-tags/form-and-input-fields).

So, now that we have the design ready it’s time to bind it to the backend.

## Binding

<figure><img src="/files/oOvwZkMlQx5Zw32ZcUAo" alt=""><figcaption></figcaption></figure>

We are going to set up authentication connecting the design elements with the auth API requests that we imported before.

1. In Bravo Studio, open your app and enter the **Data binding** screen
2. On the left panel, select \***Email** element
3. Open the **Input Destination** panel on the right
4. Select **Fitness Use Case** → **Auth · Login** → **email**
5. Repeat with \***Password**. Select **password**

Now both variables are bound to the input elements.

<figure><img src="/files/VjOVLOvg7VlVW2vMfk0A" alt=""><figcaption></figcaption></figure>

We’ll proceed to set the token returned by the login request to the **accessToken** variable:

1. Select the *default* layer under the *CTA* frame on the left sidebar
2. Open the **Form response action** panel on the right
3. Select **Set Access Token** in the **On Success** dropdown
4. Type **${accessToken}** in the input below it

You’re all set!

## Bravo Vision

It’s time to test the login! [Download Bravo Vision](https://docs.bravostudio.app/get-started/bravo-vision-previewer) if you don’t have it already.

1. Open Bravo Vision and login with your Bravo credentials
2. Open **Fitness Use Case** app
3. Continue the intro page
4. In the login page, enter **<test@test.com>** as email and **12345678** as password
5. Click the **LOGIN** button and you should be logged in!

## Binding the home page

<figure><img src="/files/FbM1ZMOXLOmJRIkXU4NN" alt=""><figcaption></figcaption></figure>

The home page has three elements bound to API requests:

* List of categories → **Workout categories · List**
* Premium workout card → **Workouts · List premium**
* List of workouts → **Workouts · List**

Let’s connect the visual elements to the data!

### **List of categories**

1. Select **Category slide** on the left sidebar
2. Open the **List Item** property on the right
3. Select **Fitness Use Case** → **Workouts categories · List** → **data**
4. For \***Name (IMAGE)**, select the same request and the **image url** param for the **Image** property
5. Repeat for \***Title,** select **name** for **Text**

### Premium workout card

1. Select **Premium workout card** on the left sidebar
2. Open **List Item** property on the right
3. Select **Fitness Use Case** → **Workouts · List premium** → **data**
4. Bind \***Background image (IMAGE)** to **video\_thumbnail url** for **Image** property
5. Repeat the binding to match the following:
   1. \***Workout short description** to **description**
   2. \***Workout title** to **title**
   3. \***Workout category** to **category name**

### List of workouts

1. Select **Featured workout card** on the left sidebar
2. Open **List Item** property on the right
3. Select **Fitness Use Case** → **Workouts · List Featured** → **data**
4. Repeat steps 4 and 5 from previous binding (Premium workout card)

Now go to Bravo Vision and refresh the homepage, you will see the elements returned by the database 🎉

{% hint style="info" %}
For this tutorial we are not covering the complete binding of the app. Feel free to explore the API requests and continue the process on the rest of the app screens. If you have any question feel free to [ask it in the Bravo community](https://community.bravostudio.app/).
{% endhint %}

You’ll have seen that we bound the premium content, although for the moment every user will see it, and that’s not what we want to happen. It’s time to configure In-app purchases!

## Set up in-app purchase

<figure><img src="/files/eznaZNmO5sBvqAkXBg7V" alt=""><figcaption></figcaption></figure>

To allow app users to purchase subscriptions, Bravo integrates RevenueCat, a platform that provide a subscription backend and wrapper around Apple's StoreKit and Google Play Billing. With RevenueCat you can make sure your users pay for accessing specific pages and content. Instead of having one set up for Android and another for iOS, Bravo connects to RevenueCat to have both platforms available in your app with just one connection.

<figure><img src="/files/OrevxMltqzEyE4JDqyfd" alt=""><figcaption></figcaption></figure>

Our app will be able to do the following:

* Show Upgrade buttons to free users
* Show a paywall to unlock paid content, showing the price from the AppStore of GooglePlay (in the user’s currency)
* Show a list of premium workouts to paid users

## App Store Connect configuration

{% hint style="info" %}
We are not covering the Android/Google Play set up. Check out the [full in-app purchase documentation](https://docs.bravostudio.app/integrations/in-app-purchases-and-subscriptions-revenuecat#setup-revenuecat-app) to learn more.
{% endhint %}

First off we need to create an app in App Store Connect and generate some codes:

1. Follow step 2 from [our iOS publication guide](https://docs.bravostudio.app/app-publication/publishing-your-app/ios-publication-complete-process) (step 1 is optional) to generate the Certificates, Identifiers and Profiles.
2. Go to App Store Connect's [My Apps](https://appstoreconnect.apple.com/apps) page and click on the **+ button** → **New app.**

<figure><img src="/files/4bWZD8V5DNbJgGEw7xwz" alt=""><figcaption></figcaption></figure>

1. In **Platforms** select **iOS.**
2. Set a **Name** and **Primary Language.**
3. Select the Bundle ID generated previously.
4. Set an **SKU**. For example a date: *20230312.*
5. Select **Full Access** (it’s up to you though) and click **Create.**

### Generate subscription

Your app has been created! Now let’s generate the subscription.

{% hint style="info" %}
To keep things simple, we are going to create just one subscription for this tutorial. If you want to create more, check out [RevenueCat’s documentation](https://www.revenuecat.com/docs/ios-products).
{% endhint %}

1. In the sidebar, select **Subscriptions** under Features, then click the **+** button to create a Subscription Group.
2. Set *Fitness premium* as **Reference Name.**

<figure><img src="/files/dPPkEQevGzvymAGVP7J9" alt=""><figcaption></figcaption></figure>

3. After creating your Subscription Group, click the **+** symbol to add a new subscription to the group.
4. Set *Full access monthly* as **Reference Name** and *fa\_699\_1m* as **Product ID.**
5. Click **Create.**

{% hint style="info" %}
The product Id is a unique alphanumeric ID that is used for accessing your product in development and syncing with RevenueCat. After you use a Product ID for one product in App Store Connect, it can’t be used again across any of your apps, even if the product is deleted. It helps to be a little organized here from the beginning - we recommend using a consistent naming scheme across all of your product identifiers such as:

**\<app>\_\<price>\_\<duration>**
{% endhint %}

### **Set subscription duration**

Once your product is created, you'll be able to set the duration of the auto-renewable subscription. Use the duration dropdown to choose **1 month**, and click **Save**.

### **Set subscription price**

1. Click **Add Subscription Price** in the **Subscription Prices** section.
2. Select your desired **Country or Region** and 6,99 as **Price**
3. Click **Next.** Apple will automatically set the price in all App Store regions based off the price and currency you selected. You'll have the option to edit these, but we recommend sticking with the defaults. When done, click **Create**.
4. Click **Save.**

### **Adding Localization**

This is the name and description of the in-app purchase that the user will see.

1. In the App Store Information section, click the '**+**' icon next to Localization
2. Set *Full access* as **Display Name**
3. Set *Get access to all videos and recipes* as **Description**

The Subscription Display Name and Description **will be visible to the user** on the App Store and in their subscription management settings

### **Reviewer Information**

Since we are just testing the set up in Testflight, we will skip this step. You’ll need it once you want to get your app published.

### Subscription Groups

When you configure products for the first time and just set up a subscription group, you may see a warning in App Store Connect:

> Before you can submit your in-app purchase for review, you must add at least one localization to your subscription group. Add localizations

Clicking on the **Add localizations** link will take you to the Subscription Group configuration. Similar to how you added localizations to the product, you'll need to add localizations to the Subscription Group as well.

Don't forget to click **Save** before exiting.

### App-Specific Shared Secret

Generate an App-Specific Shared Secret [following this guide](https://www.revenuecat.com/docs/itunesconnect-app-specific-shared-secret).

### In-App Purchase Key

Generate an In-App Purchase Key [following this guide](https://www.revenuecat.com/docs/in-app-purchase-key-configuration).

Congratulations! The Apple Store Connect set up is ready 🎉

## RevenueCat configuration

1. Sign up for a new RevenueCat account [here](https://app.revenuecat.com/).
2. Navigate to the RevenueCat dashboard and [add a new project](https://app.revenuecat.com/overview)  from the dropdown in the top navigation menu called *Projects*.
3. Set *Fitness App Use Case* as **Project Name.**
4. From **Project Settings → Apps** in the left menu of the project dashboard, select **App Store**.

<figure><img src="/files/WHuJuMPyq8pyNhoAKUeT" alt=""><figcaption></figcaption></figure>

5. Set *Fitness App Use Case* as **App Name**.
6. Set your app’s bundle ID (the one in Apple Store Connect) as **App Bundle ID**.
7. Set the **App-Specific Shared Secret** and the **In-App Purchase Key** generated before.
8. Click **Save**.

### Products, Entitlements and Offerings

{% hint style="info" %}
Learn more about [how to configure products in RevenueCat](https://www.revenuecat.com/docs/entitlements).
{% endhint %}

1. In the **Products and pricing** menu of the left, click on **Products.**
2. Click on **+ New Product.**
3. Set *fa\_699\_1m* as **Identifier**, \*\*which the Product ID created before in Apple Store Connect.
4. Click **Create Product**.
5. Now go to **Entitlements** and click on **+ New**.

<figure><img src="/files/vrhhz6XPJVQKVRWaMr2E" alt=""><figcaption></figcaption></figure>

6. In **Identifier** set *full*.
7. In **Description** set **Full access to all videos and recipes.**
8. Click **Add**.
9. Now click on the *full* row to open the entitlement just created.
10. Click on **Attach**

<figure><img src="/files/aILzheXPhrVrZ8A4rHWi" alt=""><figcaption></figcaption></figure>

11. Click **Choose a product** and select *fa\_699\_1m - Fitness App Use Case*
12. Click **Add**.
13. Go to **Offerings** and click on **+ New.**
14. Set **default** as Identifier. This is critical, Bravo supports only this identifier.
15. Set any description and click **Add**.
16. Now click on the *default* row to open the offering just created.
17. Create a **+ New** package.
18. Select **Custom** Identifier and set it as *full.* Set **Description** as *Full access to all videos and recipes.*
19. Click on the table row just created corresponding with the *full* identifier.
20. Attach the product *fa\_699\_1m.*

RevenueCat set up is done! 🎉

### Review the design tags for In-app Purchase

Let’s open the Figma file and take a look on how it’s been bravorized. For example, the Home page has a container that we want to show only to premium users. We use the `[require:purchase:full]` tag for that. Note that full is the offering identifier we set in RevenueCat.

<figure><img src="/files/nZsCWJDhY4nAjzspYKej" alt=""><figcaption></figcaption></figure>

Now check out the Paywall page. We are using several tags:

* <mark style="color:red;">`[page:paywall]`</mark> for the main frame, to enable purchase actions.
* <mark style="color:red;">`[action:purchase:full]`</mark> to trigger the purchase action for the *full* offering we created in RevenueCat.
* <mark style="color:red;">`[price:full]`</mark> and <mark style="color:red;">`{price}`</mark> to show the price of the *full* offering in the user’s currency.

<figure><img src="/files/uwAZn34X5KMJeSCwPBP1" alt=""><figcaption></figcaption></figure>

Feel free to explore the design to learn more. For example, Upgrade buttons have the tag <mark style="color:red;">`[require:purchase:none]`</mark> to be visible only to free users.

{% hint style="info" %}
If you want to learn all you can do with Bravo and RevenueCat’s integration, check out the [In-app purchase documentation](https://docs.bravostudio.app/integrations/in-app-purchases-and-subscriptions-revenuecat).
{% endhint %}

## Enable RevenueCat in Bravo

The final step is to connect your Bravo app with RevenueCat.

1. Go to RevenueCat and copy the **API Key.**

<figure><img src="/files/NwLdSEz1ljl2qHV78fHp" alt=""><figcaption></figcaption></figure>

2. In Bravo Studio, go to your app → Integrations.

<figure><img src="/files/BPTVyJoiqleMex4g7hOb" alt=""><figcaption></figcaption></figure>

3. In **Payments**, enable **RevenueCat**.
4. Paste the key in **Apple (iOS) API Key.**
5. Click **Save**.

And we are done! 🎉

## TestFlight

In order to test In-app purchase on iOS, we need to use TestFlight. TestFlight is a platform developed by Apple that allows developers to distribute and test pre-release versions of their apps to a limited group of external testers before releasing them to the general public. It also allows to receive feedback from the group of testers.

#### Generate the IPA

1. In Bravo Studio, go to **your app** → **Publish** → **iOS**.
2. Fill the **Bundle ID** and **certificates** generated at the beginning of the tutorial.
3. Click on **Get IPA**.

In 15-20min you'll receive your IPA ready to be uploaded to Apple Store Connect.

{% hint style="info" %}
Remember that for each IPA you generate, the Build Number on the Bravo publication form needs to be higher than the previous one.
{% endhint %}

#### **Upload the app via Transporter**

1. Download the [Transporter app here](https://apps.apple.com/es/app/transporter/id1450874784?l=en\&mt=12) (available on the Mac App Store).
2. **Open Transporter** from your computer, enter your Apple credentials and **upload the .ipa file**
3. Click **Deliver.**

It may take some time for the package to appear in App Store Connect (can be minutes or up to an hour). You can check the status in the Activity section on the App Store Connect page.

*If you get an alert with the message that some tools are missing and you need Xcode, you will need to install* [*Xcode*](https://developer.apple.com/xcode/) *from the Mac App Store.*

#### **Add test users**

1. In **App Store Connect** click **Users and Access** at the top.
2. Click the **+** button
3. Fill the **New User** form. You can add yourself here. Make sure you check the app(s) you want them to have access to.
4. Click **Invite**.

The user will need to open the email and click on **Accept invitation**.

#### **Add testers to Internal Testing**

Users added to this group can access the app without needing Apple to do any review process. It's the quickest way to test your app with a bunch of users (up to 10.000).

1. In **App Store Connect**, go to **Apps** and **click the app** you want to add testers to.
2. At the top tab menu, click **Testflight**,
3. In **Internal testing**, click the **+** button.
4. In the **Create New Internal Group** modal window, enter a **name**. For example, "Testers" and click **Create**.
5. A new section will appear named as the group created. click the **+** button right after the title.
6. In the **Add Testers to the Group** modal window, **select** the testers and click **Add**.

The users will need to click on the **View in TestFlight** button from the email they received to see the app in TestFlight. Then accept and install the app.

{% hint style="info" %}
Let us know if you have any questions in the [Bravo community](https://community.bravostudio.app/)!
{% 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.bravostudio.app/get-started/help-and-tutorials/app-cases/how-to-build-a-fitness-app-with-bravo-xano-and-revenuecat.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.
