FittyAI Integration — React Native
FittyAI lets you embed a fully‑featured virtual trainer inside your application in minutes. Integration takes just:
- Build the workout URL
- Drop it into a suitable container
- Listen for a handful of Event Bridge messages
Prerequisites
Credential | How to obtain |
---|---|
clientId | Given during onboarding |
secret | Given during onboarding (used to sign your JWT) |
To get
workoutId
either fetch possible workouts using Workouts API or store enabled for your client workouts in your storage.
Project Setup
npx react-native init FittyDemo
cd FittyDemo
npm install react-native-webview uuid
Inject env variables with react-native-config
or pass as props.
Preparation
⚠️ Important: Acquiring the JWT must be managed on your backend server. It’s essential because this process involves sending your secret. For security, never store or send secrets from a client device.
Read the instructions to receive your JWT here.
Upon retrieval, the JWT will resemble:
const userToken = "eyJhbGciOiJIUzI1NiIsInR5cCI...";
import { v4 as uuidv4 } from "uuid";
const sessionId = uuidv4();
const env = "prod";
Embedding the Player (React Native)
import React, { useRef } from 'react';
import { View, StyleSheet } from 'react-native';
import { WebView } from 'react-native-webview';
export default function FittyWorkoutMobile({ workoutId }) {
const webRef = useRef(null);
const url = `https://${env}.fittyai.com/web/${clientId}/${workoutId}/${sessionId}?JWT=${userToken}`;
const onMessage = event => {
const data = JSON.parse(event.nativeEvent.data || '{}');
if (data.type === 'sessionEnd') {
// fetch results using sessionId and our session API endpoint
}
};
return (
<View style={styles.container}>
<WebView
ref={webRef}
source=
style={styles.webview} // full-screen
javaScriptEnabled
originWhitelist={[`https://${env}.fittyai.com`]}
onMessage={onMessage}
allowsInlineMediaPlayback
mediaPlaybackRequiresUserAction={false}
allowsFullscreenVideo
// Autogrant camera permission (Android 12+) if host matches:
mediaCapturePermissionGrantType="grantIfSameHostElsePrompt"
/>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
webview: { flex: 1 },
});
Event Bridge
Event | Payload | When |
---|---|---|
initiationCompleted |
{ type: "initiationCompleted" } |
After internal bootstrap |
indexUpdated |
{ type: "indexUpdated", index: number } |
Whenever the active exercise changes |
closeRequested |
{ type: "closeRequested" } |
User hit X and the URL contained suppressFinish=true |
sessionEnd |
{ type: "sessionEnd" } |
Workout finished or host called nativeBridge.close() |
Fetching the Results
After sessionEnd
call the Get Session endpoint:
GET /v1/{clientName}/sessions/{sessionId}
fetch(`/v1/<clientId>/sessions/${sessionId}`, {
headers: { Authorization: 'Bearer <jwt>' }
}).then(r => r.json()).then(console.log);
See the full schema in the Get Session docs.
Optional URL Query Parameters
Add these only when you need them—they all work independently.
Parameter | Purpose | Example |
---|---|---|
eventIndex |
Load the workout starting from a specific exercise | ?eventIndex=5 |
suppressFinish |
Use suppressFinish=true to disable our workout summary screen and show your custom summary screen; emits closeRequested instead |
?suppressFinish=true |
Simply append one or more to the iframe URL (order doesn’t matter).