### Initialize and Start Workout (Vanilla JS) Source: https://workoutkit.fizzup.com/web/usage.html Use this pattern in plain HTML or server-rendered pages to initialize the WorkoutKit SDK and start a workout. It logs various workout events to the console. ```javascript workoutkit.init('https://cloud.YourCompany.fizzup.com') workoutkit.start({ workoutId: '4RGZ7S46', soundpack: 'none', onWorkoutQuit: function () { console.log('Event received: workout quit') }, onWorkoutSave: function (workoutData) { console.log('Event received: workout save', workoutData) }, onWorkoutEvent: function (action, payload) { console.log('Event received:', action, payload) }, }) ``` -------------------------------- ### workoutkit.start(options) Source: https://workoutkit.fizzup.com/web/reference.html Starts a workout session with the specified options. This method launches the WorkoutKit iframe and begins the workout experience. ```APIDOC ## workoutkit.start(options) ### Description Starts a workout session. ### Method `start` ### Parameters #### Request Body - **options** (object) - Required - Configuration options for the workout session. - **workoutId** (string) - Required - WorkoutKit workout identifier to launch. - **soundpack** (string) - Optional - Sound theme for the workout experience. Supported values include `none`, `zen`, `original`, `new`, `whistle`. - **getAccessToken** (function) - Optional - Async callback returning a backend-issued access token. - **onWorkoutQuit** (function) - Optional - Callback called when the user quits the workout. - **onWorkoutSave** (function) - Optional - Callback called when workout data is saved. - **onWorkoutEvent** (function) - Optional - Generic callback receiving event name and payload. ``` -------------------------------- ### Initialize and Start Workout with WorkoutKit SDK Source: https://workoutkit.fizzup.com/web/usage.html This component initializes the WorkoutKit SDK and provides functionality to start a workout. It fetches session content using Apollo Client before launching the workout. Ensure the SDK script is loaded and initialized before attempting to start a workout. The `accessTokenProvider` should be replaced with actual token retrieval logic. ```tsx import { useLazyQuery } from '@apollo/client/react' import { useEffect, useState } from 'react' import { GET_SESSION_CONTENT, type GetSessionContentData, type GetSessionContentVariables, type WorkoutPreview, } from './queries' import { WORKOUTKIT_BASE_URL } from './WorkoutKitGraphQLProvider' declare global { interface Window { workoutkit: { init: (baseUrl: string) => void start: (options: { workoutId: string soundpack?: string getAccessToken?: () => Promise onWorkoutQuit?: () => void onWorkoutSave?: (workoutData: unknown) => void onWorkoutEvent?: (action: string, payload: unknown) => void }) => void } } } type WorkoutPreviewItemProps = { workout: WorkoutPreview } const SDK_URL = 'https://cdn.fizzup.com/js/workoutkit-sdk/1.0.0/sdk.js' async function accessTokenProvider() { // Replace with your own end-user token retrieval when your integration needs it. return 'yourEndUserAccessToken' } function formatDuration(seconds: number) { const minutes = Math.round(seconds / 60) return `${minutes} min` } export function WorkoutPreviewItem({ workout }: WorkoutPreviewItemProps) { const [isReady, setIsReady] = useState(false) const [hasClickedStart, setHasClickedStart] = useState(false) const [loadWorkoutSession, { loading: isLoadingSession }] = useLazyQuery< GetSessionContentData, GetSessionContentVariables >(GET_SESSION_CONTENT, { fetchPolicy: 'network-only', }) useEffect(() => { const existingScript = document.querySelector(`script[src="${SDK_URL}"]`) const initialize = () => { window.workoutkit.init(WORKOUTKIT_BASE_URL) setIsReady(true) } if (existingScript) { if (window.workoutkit) { initialize() } else { existingScript.addEventListener('load', initialize, { once: true }) } return } const script = document.createElement('script') script.src = SDK_URL script.async = true script.onload = initialize document.body.appendChild(script) return () => { script.onload = null } }, []) const startWorkout = async () => { setHasClickedStart(true) if (!window.workoutkit || !isReady) { return } const response = await loadWorkoutSession({ variables: { id: workout.id }, }) if (!response.data?.publicWorkoutSession) { throw new Error('WorkoutKit session content is missing') } window.workoutkit.start({ workoutId: workout.id, soundpack: 'none', getAccessToken: accessTokenProvider, onWorkoutQuit: () => { console.log('Workout quit', workout.id) }, onWorkoutSave: (workoutData) => { console.log('Workout saved', workout.id, workoutData) }, onWorkoutEvent: (action, payload) => { console.log('Workout event', action, payload) }, }) } const isStarting = hasClickedStart && (!isReady || isLoadingSession) return ( ) } ``` -------------------------------- ### Start Workout Session Source: https://workoutkit.fizzup.com/web/reference.html Starts a workout session with specified options. Requires a workout ID and can optionally configure soundpacks, access tokens, and callbacks for workout events. ```javascript workoutkit.start({ workoutId: '4RGZ7S46', soundpack: 'none', getAccessToken: async function () { return 'your-access-token' }, onWorkoutQuit: function () {}, onWorkoutSave: function (workoutData) {}, onWorkoutEvent: function (action, payload) {}, }) ``` -------------------------------- ### Install Apollo Client Dependencies Source: https://workoutkit.fizzup.com/web/usage.html Install the necessary Apollo Client packages for React applications using npm. ```bash npm install @apollo/client graphql ``` -------------------------------- ### Start a Workout with Options Source: https://workoutkit.fizzup.com/web/quickstart.html Initiate a workout using workoutkit.start(), providing a workout ID and necessary options like soundpack, access token retrieval, and event callbacks. ```html Intégration FizzUp WorkoutKit

Chargement de votre entrainement

``` -------------------------------- ### GraphQL Query Example Source: https://workoutkit.fizzup.com/api/graphql-overview.html This example demonstrates a GraphQL query to fetch session content, including details for both classic and video workout types. The query uses a variable for the workout ID and specifies configuration options. ```APIDOC ## GraphQL Query ### Description This query retrieves detailed information about a specific workout session, including its ID, name, duration, and specific content like sections for block sessions or video URLs for video sessions. It supports polymorphic responses, allowing clients to handle different session types. ### Query ```graphql query GetSessionContent($id: ID!) { publicWorkoutSession( globalId: $id, configuration: { difficulty: EASY } ) { __typename ... on WorkoutBlockSession { id: globalId name duration sections { id name type } } ... on WorkoutVideoSession { id name duration video { url } } } } ``` ### Variables - **id** (ID!) - The global ID of the workout session to retrieve. ``` -------------------------------- ### Example Usage in a React Page Source: https://workoutkit.fizzup.com/web/usage.html Demonstrates how to use the WorkoutKitPlayer component in a React page, including a custom accessTokenProvider function for fetching authentication tokens. ```typescript import { WorkoutKitPlayer } from './WorkoutKitPlayer' async function accessTokenProvider() { const response = await fetch('/api/workoutkit/token', { method: 'POST', credentials: 'include', }) if (!response.ok) { throw new Error('Unable to retrieve WorkoutKit access token') } const data: { accessToken?: string } = await response.json() if (!data.accessToken) { throw new Error('WorkoutKit token response is missing accessToken') } return data.accessToken } export default function WorkoutPage() { return ( { console.log('Event received: workout quit') }} onWorkoutSave={(workoutData) => { console.log('Event received: workout save', workoutData) }} onWorkoutEvent={(action, payload) => { console.log('Event received:', action, payload) }} /> ) } ``` -------------------------------- ### Example JWT Payload Source: https://workoutkit.fizzup.com/api/authentication-server-requests.html This is an example of a JWT payload that WorkoutKit expects for authenticated user-context operations. The 'sub' claim is required, while 'exp' and 'nbf' are optional but recommended. ```json { "sub": "550e8400-e29b-41d4-a716-446655440000", "exp": 1760000000, "nbf": 1759996400 } ``` -------------------------------- ### Get Sessions Query Source: https://workoutkit.fizzup.com/web/usage.html Fetches a list of workout sessions with preview information. This query is designed to be efficient by only returning essential preview fields. ```APIDOC ## GetSessions Query ### Description Fetches a list of workout sessions with preview information, filtered by tag and difficulty. ### Method POST ### Endpoint /graphql ### Parameters #### Query Parameters - **tag** (String!) - Required - The tag to filter workouts by. - **difficulty** (Difficulty!) - Required - The difficulty level to filter workouts by (EASY, NORMAL, HARD). ### Request Example ```json { "query": "query GetSessions($tag: String!, $difficulty: Difficulty!) { publicWorkouts(filters: { tag: $tag }, configuration: { difficulty: $difficulty }) { edges { node { ...WorkoutPreviewItem } } } } fragment WorkoutPreviewItem on WorkoutPreview { id: globalId type duration name format picture }", "variables": { "tag": "cardio", "difficulty": "EASY" } } ``` ### Response #### Success Response (200) - **publicWorkouts** (object) - Contains a list of workout edges. - **edges** (array) - An array of workout edges. - **node** (object) - Represents a single workout preview. - **id** (String) - The global ID of the workout. - **type** (String) - The type of the workout. - **duration** (Int) - The duration of the workout in seconds. - **name** (String) - The name of the workout. - **format** (String, optional) - The format of the workout (e.g., 'video', 'audio'). - **picture** (String, optional) - URL to a preview image for the workout. #### Response Example ```json { "data": { "publicWorkouts": { "edges": [ { "node": { "id": "workout-123", "type": "HIIT", "duration": 1800, "name": "Full Body HIIT", "format": "video", "picture": "https://example.com/image.jpg" } } ] } } } ``` ``` -------------------------------- ### List Workouts with Filters Source: https://workoutkit.fizzup.com/api/queries.html Use this query to list available workouts, applying filters such as tags and difficulty configurations. This is a common starting point for workout discovery. ```graphql query GetSessions { publicWorkouts(filters: { tag: "demo" }, configuration: { difficulty: EASY }) { edges { node { ...WorkoutPreviewItem } } } } ``` -------------------------------- ### Get one workout preview Source: https://workoutkit.fizzup.com/api/queries.html This query retrieves a preview of a single workout using its global ID. ```APIDOC ## Get one workout preview ### Description This query retrieves a preview of a single workout using its global ID. ### Method POST ### Endpoint /graphql ### Query Parameters - **id** (ID!) - Required - The global ID of the workout. ### Request Example ```graphql query GetSession($id: ID!) { publicWorkout(globalId: $id) { ...WorkoutPreviewItem } } fragment WorkoutPreviewItem on WorkoutPreview { id: globalId type duration name format picture } ``` ``` -------------------------------- ### GraphQL API Server Response Example Source: https://workoutkit.fizzup.com/api/graphql-overview.html This JSON object represents a typical response from the GraphQL API for a `WorkoutBlockSession`. It mirrors the structure of the query, returning only the requested fields. ```APIDOC ## API Server Response ### Description This is an example of a successful JSON response from the GraphQL API when querying for session content. The response structure directly maps to the fields requested in the GraphQL query, including a `__typename` field to identify the concrete type of the session. ### Response Body ```json { "data": { "publicWorkoutSession": { "__typename": "WorkoutBlockSession", "id": "wrk_123", "name": "Core Blast", "duration": 1200, "sections": [ { "id": "sec_1", "name": "Warm-up", "type": "WARMUP" }, { "id": "sec_2", "name": "Main Set", "type": "WORK" } ] } } } ``` ``` -------------------------------- ### Fetch Schema and Generate Models with Apollo CLI Source: https://workoutkit.fizzup.com/ios/quickstart.html Use these commands to fetch the GraphQL schema and generate Swift models for WorkoutKit. Ensure the apollo-ios-cli is installed and configured in your project. ```bash ./apollo-ios-cli fetch-schema --path SampleApp/apollo-codegen-config.json ./apollo-ios-cli generate --path SampleApp/apollo-codegen-config.json ``` -------------------------------- ### React Workout Player Component Source: https://workoutkit.fizzup.com/web/usage.html A React component that loads the SDK script, initializes WorkoutKit, and starts a workout on button click. It uses an external accessTokenProvider for authentication. ```typescript import { useEffect, useState } from 'react' declare global { interface Window { workoutkit: { init: (baseUrl: string) => void start: (options: { workoutId: string soundpack?: string getAccessToken?: () => Promise onWorkoutQuit?: () => void onWorkoutSave?: (workoutData: unknown) => void onWorkoutEvent?: (action: string, payload: unknown) => void }) => void close: () => void } } } type WorkoutKitPlayerProps = { baseUrl: string workoutId: string soundpack?: 'none' | 'zen' | 'original' | 'new' | 'whistle' accessTokenProvider?: () => Promise onWorkoutQuit?: () => void onWorkoutSave?: (workoutData: unknown) => void onWorkoutEvent?: (action: string, payload: unknown) => void } const SDK_URL = 'https://cdn.fizzup.com/js/workoutkit-sdk/1.0.0/sdk.js' export function WorkoutKitPlayer({ baseUrl, workoutId, soundpack = 'original', accessTokenProvider, onWorkoutQuit, onWorkoutSave, onWorkoutEvent, }: WorkoutKitPlayerProps) { const [isReady, setIsReady] = useState(false) useEffect(() => { const existingScript = document.querySelector(`script[src="${SDK_URL}"]`) const initialize = () => { window.workoutkit.init(baseUrl) setIsReady(true) } if (existingScript) { if (window.workoutkit) { initialize() } else { existingScript.addEventListener('load', initialize, { once: true }) } return } const script = document.createElement('script') script.src = SDK_URL script.async = true script.onload = initialize document.body.appendChild(script) return () => { script.onload = null } }, [baseUrl]) const startWorkout = () => { window.workoutkit.start({ workoutId, soundpack, getAccessToken: accessTokenProvider, onWorkoutQuit, onWorkoutSave, onWorkoutEvent, }) } return ( ) } ``` -------------------------------- ### Get Session Content Query Source: https://workoutkit.fizzup.com/web/usage.html Fetches the full details of a specific workout session, including its structure, exercises, and media. This query is intended for when the complete session data is required. ```APIDOC ## GetSessionContent Query ### Description Fetches the detailed content of a specific workout session identified by its ID. ### Method POST ### Endpoint /graphql ### Parameters #### Query Parameters - **id** (ID!) - Required - The global ID of the workout session. ### Request Example ```json { "query": "query GetSessionContent($id: ID!) { publicWorkoutSession(globalId: $id, configuration: { difficulty: EASY }) { __typename ... on WorkoutBlockSession { ...WorkoutBlockSessionItem } ... on WorkoutVideoSession { ...WorkoutVideoSessionItem } } } fragment WorkoutBlockSessionItem on WorkoutBlockSession { audioSets { ...AudioSetItem } duration exercises { ...WorkoutExerciseItem } id: globalId sections { ...WorkoutSectionItem } name type } fragment AudioSetItem on AudioSet { duration audioFile id text textPhonetic } fragment WorkoutExerciseItem on WorkoutExercise { id name execution duration cover } fragment WorkoutSectionItem on WorkoutSection { id type duration calories executionMode name optional premium tasks { ... on TaskExercise { audioSets { ...AudioSetsItem } effortType noSeries nbSeries exerciseId side nbRepetition duration asymmetricType progressionSegment video { ...WorkoutVideoItem } } ... on TaskRest { audioSets { ...AudioSetsItem } restTaskType restTime video { ...WorkoutVideoItem } } } } fragment WorkoutVideoItem on WorkoutVideo { cover textPrimaryColor textSecondaryColor tintColor video } fragment AudioSetsItem on AudioSetTask { audioSetsId timestamp type } fragment WorkoutVideoSessionItem on WorkoutVideoSession { duration id name reference sections { ...WorkoutVideoSessionSectionItem } video { ...WorkoutVideoSessionVideoItem } } fragment WorkoutVideoSessionSectionItem on WorkoutVideoSessionSection { id type start end calories optional name skipLabel } fragment WorkoutVideoSessionVideoItem on WorkoutVideoSessionVideo { cover end start textPrimaryColor url }", "variables": { "id": "workout-session-456" } } ``` ### Response #### Success Response (200) - **publicWorkoutSession** (object) - The detailed information about the workout session. - **__typename** (String) - The type of the workout session (e.g., 'WorkoutBlockSession', 'WorkoutVideoSession'). - **id** (String) - The global ID of the workout session. - **name** (String) - The name of the workout session. - **duration** (Int) - The duration of the workout session in seconds. - **sections** (array) - An array of sections within the workout session. - **audioSets** (array, for WorkoutBlockSession) - Audio sets associated with the session. - **exercises** (array, for WorkoutBlockSession) - Exercises included in the session. - **reference** (String, for WorkoutVideoSession) - A reference identifier for the video session. - **video** (object, for WorkoutVideoSession) - Video details for the session. #### Response Example ```json { "data": { "publicWorkoutSession": { "__typename": "WorkoutBlockSession", "id": "workout-session-456", "name": "Advanced Strength Training", "duration": 3600, "sections": [ { "id": "section-a", "type": "exercise", "duration": 60, "calories": 100, "executionMode": "timed", "name": "Squats", "optional": false, "premium": false, "tasks": [ { "effortType": "strength", "noSeries": 3, "nbSeries": 10, "exerciseId": "ex-squat", "side": "left", "nbRepetition": 10, "duration": 30, "asymmetricType": "none", "progressionSegment": "base", "video": { "cover": "https://example.com/squat_cover.jpg", "textPrimaryColor": "#FFFFFF", "textSecondaryColor": "#CCCCCC", "tintColor": "#000000", "video": "https://example.com/squat.mp4" } } ] } ] } } } ``` ``` -------------------------------- ### Create GoFragment Instance Source: https://workoutkit.fizzup.com/android/reference/fragments.html Use `GoFragment.newInstance` for classic workouts. Requires workout content, configuration, and a JWT token. ```kotlin GoFragment.newInstance(workoutContent, workoutConfig, jwtToken) ``` -------------------------------- ### Create WorkoutVideoFragment Instance Source: https://workoutkit.fizzup.com/android/reference/fragments.html Use `WorkoutVideoFragment.newInstance` for streaming video workouts. Requires workout content, configuration, and a JWT token. ```kotlin WorkoutVideoFragment.newInstance(workoutContent, workoutConfig, jwtToken) ``` -------------------------------- ### workoutkit.init(baseUrl) Source: https://workoutkit.fizzup.com/web/reference.html Initializes the SDK with your WorkoutKit base URL. This must be called before any other WorkoutKit methods. ```APIDOC ## workoutkit.init(baseUrl) ### Description Initializes the SDK with your WorkoutKit base URL. ### Method `init` ### Parameters #### Path Parameters - **baseUrl** (string) - Required - The base URL for WorkoutKit services. ``` -------------------------------- ### Get session payload for launch Source: https://workoutkit.fizzup.com/api/queries.html This query retrieves the session payload required for launching a workout, supporting both block and video sessions. ```APIDOC ## Get session payload for launch ### Description This query retrieves the session payload required for launching a workout, supporting both block and video sessions. This is the important query for launch flows as it returns the session payload consumed by the SDK. ### Method POST ### Endpoint /graphql ### Query Parameters - **id** (ID!) - Required - The global ID of the workout session. - **configuration** (object) - Optional - Configuration for the session, e.g., `{ difficulty: EASY }` ### Request Example ```graphql query GetSessionContent($id: ID!) { publicWorkoutSession(globalId: $id, configuration: { difficulty: EASY }) { ... on WorkoutBlockSession { ...WorkoutBlockSessionItem } ... on WorkoutVideoSession { ...WorkoutVideoSessionItem } } } ``` ### Response #### Success Response (200) - **publicWorkoutSession** - The session payload, which may include a `WorkoutKitToken` valid for 1 day. ``` -------------------------------- ### Create WorkoutVideoFragment Instance Source: https://workoutkit.fizzup.com/android/guides/video-workouts.html Instantiate WorkoutVideoFragment with workout content, configuration, and JWT token. Ensure GraphQL/JWT preparation follows the classic workouts flow. ```kotlin val videoFragment = WorkoutVideoFragment.newInstance( workoutContent, // GraphQL payload workoutConfig, // JSON configuration jwtToken // JWT token ) ``` -------------------------------- ### Initialize WorkoutKit Source: https://workoutkit.fizzup.com/web/quickstart.html Call workoutkit.init() with your WorkoutKit base URL to initialize the SDK. ```javascript workoutkit.init('https://cloud.YourCompany.fizzup.com') ``` -------------------------------- ### Create GoFragment Instance Source: https://workoutkit.fizzup.com/android/guides/classic-workouts.html Instantiate the GoFragment with the GraphQL workout content, JSON configuration, and JWT token. This fragment is used to render classic workouts. ```kotlin val goFragment = GoFragment.newInstance( workoutContent, // GraphQL payload workoutConfig, // JSON configuration jwtToken // JWT token ) ``` -------------------------------- ### Build Fragment Configuration Source: https://workoutkit.fizzup.com/android/quickstart.html Construct a JSONObject for workout configuration, including human audio coach availability and custom text for workout states. This is used when creating workout fragments. ```kotlin val workoutConfig = JSONObject().apply { put("isHumanAudioCoachAvailable", false) put( "texts", JSONObject( mapOf( "startWorkoutCTA" to "Let\'s go!", "endedWorkoutTitle" to "Well done!", "saveWorkoutCTA" to "Close" ) ) ) } ``` -------------------------------- ### Add GitHub Credentials for Package Download Source: https://workoutkit.fizzup.com/android/installation.html Configure your local.properties file with your GitHub username and token. Never commit these credentials to version control. ```properties GithubUser=$YOUR_GITHUB_USERNAME GithubToken=$YOUR_GITHUB_TOKEN ``` -------------------------------- ### Create Classic Workout Fragment Source: https://workoutkit.fizzup.com/android/quickstart.html Instantiate a `GoFragment` for classic workout sessions, passing the workout content, configuration, and JWT token. This fragment is then attached to your activity container. ```kotlin val goFragment = GoFragment.newInstance( workoutContent, workoutConfig, jwtToken ) ``` -------------------------------- ### Configure Workout Controllers Source: https://workoutkit.fizzup.com/ios/guides/customization.html Provide a configuration dictionary to `GoModeController` and `GoVideoController` during initialization to customize CTA labels and completion text. ```swift let configuration: [String: Any] = [ "startWorkoutCTA": "Start now", "endedWorkoutTitle": "Great job!", "saveWorkoutCTA": "Continue" ] ``` -------------------------------- ### Get Single Workout Preview by ID Source: https://workoutkit.fizzup.com/api/queries.html Retrieve a specific workout's preview details using its unique global ID. This query is useful when you need information about a single workout. ```graphql query GetSession($id: ID!) { publicWorkout(globalId: $id) { ...WorkoutPreviewItem } } ``` -------------------------------- ### Instantiate Workout Controllers Source: https://workoutkit.fizzup.com/ios/quickstart.html Dynamically instantiate either `MonGoModeController` or `MonVideoGoController` based on the workout session type. This code snippet demonstrates how to handle different workout session payloads and present the appropriate controller. ```swift let controller: UIViewController if response.data?.publicWorkoutSession.asWorkoutBlockSession != nil { controller = try await MonGoModeController(data: data, token: token) } else { controller = try await MonVideoGoController(data: data, token: token) } controller.modalPresentationStyle = .fullScreen present(controller, animated: true) ``` -------------------------------- ### Get Session Payload for Launch Source: https://workoutkit.fizzup.com/api/queries.html This query retrieves the session payload required by the SDK to launch a workout. It supports different session types and is crucial for initiating workout sessions. Fetch this query close to workout launch. ```graphql query GetSessionContent($id: ID!) { publicWorkoutSession(globalId: $id, configuration: { difficulty: EASY }) { ... on WorkoutBlockSession { ...WorkoutBlockSessionItem } ... on WorkoutVideoSession { ...WorkoutVideoSessionItem } } } ``` -------------------------------- ### Configure GraphQL Authentication Source: https://workoutkit.fizzup.com/android/quickstart.html Add your server URL and authentication key to the `local.properties` file. This file should not be committed to version control. ```properties GraphQLServerUrl=https://server.com/graphql GraphQLAuthKey=your_auth_key_here ``` -------------------------------- ### Create Video Workout Fragment Source: https://workoutkit.fizzup.com/android/quickstart.html Instantiate a `WorkoutVideoFragment` for video workout sessions, passing the workout content, configuration, and JWT token. This fragment is then attached to your activity container. ```kotlin val videoFragment = WorkoutVideoFragment.newInstance( workoutContent, workoutConfig, jwtToken ) ``` -------------------------------- ### GoFragment Source: https://workoutkit.fizzup.com/android/reference/fragments.html Use GoFragment for classic workouts. It requires workoutContent, workoutConfig, and jwtToken as input. ```APIDOC ## GoFragment ### Description Use for classic workouts. ### Constructor Pattern ```kotlin GoFragment.newInstance(workoutContent, workoutConfig, jwtToken) ``` ### Parameters * `workoutContent` (GraphQL session payload) * `workoutConfig` (JSON customization and behavior options) * `jwtToken` (A signed JWT issued by your backend) ``` -------------------------------- ### Add WorkoutKit SDK Script Source: https://workoutkit.fizzup.com/web/installation.html Include this script in your HTML before calling workoutkit.init() or workoutkit.start(). ```html ``` -------------------------------- ### AssetManager Initialization Source: https://workoutkit.fizzup.com/ios/reference/configuration.html Initializes the AssetManager with specified offline storage behavior. ```APIDOC ## `AssetManager` Initialization ### Description Creates an instance of `AssetManager` to handle regular-workout assets, with options for offline storage. ### Method - `init(storeOffline:)` ``` -------------------------------- ### Coordinate Persistence and Post-Workout Completion Source: https://workoutkit.fizzup.com/ios/guides/workout-data.html Returning your async save publisher ensures the SDK waits for your data pipeline before fully finishing the workout. ```swift override func displayPostWorkout() -> AnyPublisher { guard let savePublisher else { return super.displayPostWorkout() } return savePublisher } ``` -------------------------------- ### Initialize the Cast context at app launch Source: https://workoutkit.fizzup.com/ios/guides/google-cast-video.html Initialize GCKCastContext in your AppDelegate or app startup entry point. Configure discovery and media controls. ```swift import GoogleCast let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: "ABCDEF123")) options.physicalVolumeButtonsWillControlDeviceVolume = true options.disableDiscoveryAutostart = false let launchOptions = GCKLaunchOptions() launchOptions.androidReceiverCompatible = true options.launchOptions = launchOptions GCKCastContext.setSharedInstanceWith(options) GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = false ``` -------------------------------- ### GoModeController Source: https://workoutkit.fizzup.com/ios/reference/controllers.html `GoModeController` is the UIKit entry point for classic workouts. It provides methods for saving sessions, displaying post-workout views, quitting workouts, and integrating with host analytics and logging. ```APIDOC ## `GoModeController` (classic workouts) `GoModeController` is the UIKit entry point for classic workouts. ### Initializer ```swift init(data: Data, token: String? = nil, configuration: [String: Any]? = nil) ``` ### High-signal methods | Method | Description | |---|---| | `saveSession(state:)` | Triggered when WorkoutKit requires session persistence within the host app. | | `displayPostWorkout() -> AnyPublisher` | Called after normal workout completion (not quit). | | `quitWorkout()` | Called when workout is exited without save. | | `trackEvent(_:properties:)` | Tracking callback for host analytics integration. | | `log(_:context:)` | Debug/log callback with optional metadata context. | | `shouldDisplayCloseButton()` | UI behavior customization hook. | ``` -------------------------------- ### WorkoutKitConfig Setters and Utilities Source: https://workoutkit.fizzup.com/ios/reference/configuration.html APIs for setting values, resetting storage, and retrieving the device identifier. ```APIDOC ## `WorkoutKitConfig` Setters and Utilities ### Description Provides methods to modify persistent storage, reset settings, and access the device identifier. ### Methods - `set(_:forKey:)`: Sets supported value types for a key. - `reset()`: Resets stored defaults to SDK baseline. - `deviceId()`: Returns a stable, installation-specific WorkoutKit device identifier used for server authentication. ``` -------------------------------- ### Configure Runtime Network Interceptor Source: https://workoutkit.fizzup.com/ios/quickstart.html Customize the `DemoHeadersAddingInterceptor` in `DemoCloudClient.swift` to add necessary headers for runtime API requests, such as device ID and authorization. This is crucial for authenticated requests. ```swift func intercept(request: URLRequest, next: @Sendable (URLRequest) async throws -> Apollo.HTTPResponse) async throws -> Apollo.HTTPResponse { var newRequest = request newRequest.addValue(WorkoutKitConfig.deviceId(), forHTTPHeaderField: "X-WorkoutKit-Device") // Add your Authorization header here when required. return try await next(newRequest) } ``` -------------------------------- ### Create and Present Classic Controller Source: https://workoutkit.fizzup.com/ios/guides/classic-workouts.html Creates and presents the `MonGoModeController` if the session data resolves to a block session. `MonGoModeController` should be a subclass of `GoModeController`. ```swift if response.data?.publicWorkoutSession.asWorkoutBlockSession != nil { let controller = try await MonGoModeController(data: data, token: token) controller.modalPresentationStyle = .fullScreen present(controller, animated: true) } ``` -------------------------------- ### Configure WorkoutKit with JSON Source: https://workoutkit.fizzup.com/android/reference/configuration-options.html Use this JSON object to configure WorkoutKit Android fragments. It allows enabling voice coach prompts and customizing text for various UI elements. ```kotlin val workoutConfig = JSONObject().apply { put("isHumanAudioCoachAvailable", true) put( "texts", JSONObject( mapOf( "startWorkoutCTA" to "Let's go!", "endedWorkoutTitle" to "Great job!", "saveWorkoutCTA" to "Close" ) ) ) } ``` -------------------------------- ### GoModeController Initializer Source: https://workoutkit.fizzup.com/ios/reference/controllers.html Use this initializer for the GoModeController when integrating classic workouts. It accepts workout data, an optional authentication token, and custom configuration. ```swift init(data: Data, token: String? = nil, configuration: [String: Any]? = nil) ``` -------------------------------- ### WorkoutKitConfig Getters Source: https://workoutkit.fizzup.com/ios/reference/configuration.html APIs for reading boolean, integer, float, double, string, and generic object settings from persistent storage. ```APIDOC ## `WorkoutKitConfig` Getters ### Description Reads various data types from persistent key-value storage. ### Methods - `bool(forKey:)` - `integer(forKey:)` - `float(forKey:)` - `double(forKey:)` - `string(forKey:)` - `object(forKey:)` ``` -------------------------------- ### WorkoutKitLogInterface Source: https://workoutkit.fizzup.com/ios/reference/delegates.html `WorkoutKitLogInterface` provides host-level logging and tracking hooks for receiving debug messages and analytics events. ```APIDOC ## `WorkoutKitLogInterface` ### Description This protocol provides host-level logging and tracking hooks. ### Methods #### `log(_ message: String, context: [String: AnyHashable]?)` * **Description**: Receives debug log messages and optional metadata context. * **Parameters**: * `message` (String) - The debug log message. * `context` ([String: AnyHashable]?) - Optional metadata context. #### `trackEvent(_ event: Tracking.Event, properties: [Tracking.Property: String]?)` * **Description**: Receives structured analytics events emitted by WorkoutKit. * **Parameters**: * `event` (Tracking.Event) - The structured analytics event. * `properties` ([Tracking.Property: String]?) - Optional event properties. ``` -------------------------------- ### Configure app discovery permissions for Google Cast Source: https://workoutkit.fizzup.com/ios/guides/google-cast-video.html Declare local network and Bonjour services in Info.plist for Google Cast discovery. Replace ABCDEF123 with your receiver app ID. ```xml NSLocalNetworkUsageDescription Local network - usage description NSBonjourServices _googlecast._tcp _ABCDEF123._googlecast._tcp ``` -------------------------------- ### Detect Video Session and Launch Source: https://workoutkit.fizzup.com/ios/guides/video-workouts.html Detects if a public workout session is a video session and launches the corresponding video controller. Requires `GoVideoController` or a subclass. ```swift if response.data?.publicWorkoutSession.asWorkoutVideoSession != nil { let controller = try await MonVideoGoController(data: data, token: token) controller.modalPresentationStyle = .fullScreen present(controller, animated: true) } ``` -------------------------------- ### Retrieve WorkoutKit Access Token Source: https://workoutkit.fizzup.com/web/authentication.html Provide this function in `workoutkit.start()` when your integration requires authenticated requests. The Web SDK expects this function to retrieve the token from your backend. ```javascript getAccessToken: async function () { const response = await fetch('/api/workoutkit/token', { method: 'POST', credentials: 'include', }) if (!response.ok) { throw new Error('Unable to retrieve WorkoutKit access token') } const data = await response.json() return data.accessToken } ``` -------------------------------- ### GoVideoController Initializer Source: https://workoutkit.fizzup.com/ios/reference/controllers.html This is a common initializer variant for the GoVideoController, used for streaming workouts. It includes parameters for workout data, local stream preference, an optional token, and configuration. ```swift init(data: Data, localStream: Bool = false, token: String? = nil, configuration: [String: Any]? = nil) ``` -------------------------------- ### Set WorkoutKit Environment Variable Source: https://workoutkit.fizzup.com/web/usage.html Configure the WorkoutKit base URL using a Vite-prefixed environment variable in your `.env` file. The GraphQL endpoint is derived from this base URL. ```bash VITE_WORKOUTKIT_BASE_URL=https://cloud.YourCompany.fizzup.com ``` -------------------------------- ### WorkoutVideoFragment Source: https://workoutkit.fizzup.com/android/reference/fragments.html Use WorkoutVideoFragment for streaming video workouts. It requires workoutContent, workoutConfig, and jwtToken as input. ```APIDOC ## WorkoutVideoFragment ### Description Use for streaming video workouts. ### Constructor Pattern ```kotlin WorkoutVideoFragment.newInstance(workoutContent, workoutConfig, jwtToken) ``` ### Parameters * `workoutContent` (GraphQL session payload) * `workoutConfig` (JSON customization and behavior options) * `jwtToken` (A signed JWT issued by your backend) ``` -------------------------------- ### WorkoutKitInterface Source: https://workoutkit.fizzup.com/ios/reference/delegates.html `WorkoutKitInterface` is the core host lifecycle protocol implemented by WorkoutKit controllers. It defines methods for saving workout sessions, managing the post-workout flow, and handling workout quitting. ```APIDOC ## `WorkoutKitInterface` ### Description This protocol defines the core host lifecycle callbacks for WorkoutKit controllers. ### Methods #### `saveSession(state: SaveWorkoutState)` * **Description**: Persist session results in host backend/app logic. Call `super` in controller overrides. * **Parameters**: * `state` (SaveWorkoutState) - The state of the workout session to be saved. #### `displayPostWorkout() -> AnyPublisher` * **Description**: Return a publisher that completes when the post-workout flow is done. * **Returns**: `AnyPublisher` #### `quitWorkout()` * **Description**: Handle the quit-without-save flow. Call `super` and ensure handling of non-UI-thread invocations. **Note**: `GoModeController` and `GoVideoController` both provide default implementations for this protocol. ``` -------------------------------- ### Workout Catalog Component with GraphQL Source: https://workoutkit.fizzup.com/web/usage.html This component fetches workout sessions using Apollo Client and displays them. Ensure WorkoutKitGraphQLProvider wraps the component to provide the necessary GraphQL context. ```tsx import { useQuery } from '@apollo/client/react' import { WorkoutKitGraphQLProvider } from './WorkoutKitGraphQLProvider' import { GET_SESSIONS, type GetSessionsData, type GetSessionsVariables } from './queries' import { WorkoutPreviewItem } from './WorkoutPreviewItem' type WorkoutCatalogProps = GetSessionsVariables function WorkoutCatalog({ tag, difficulty }: WorkoutCatalogProps) { const { data, loading, error } = useQuery(GET_SESSIONS, { variables: { tag, difficulty, }, }) if (loading) { return

Loading workouts...

} if (error) { return

Unable to load workouts.

} const workouts = data?.publicWorkouts.edges.map((edge) => edge.node) ?? [] return (

Choose a workout

{workouts.map((workout) => ( ))}
) } export default function App() { return ( ) } ``` -------------------------------- ### Add GitHub Maven Repository to Root build.gradle Source: https://workoutkit.fizzup.com/android/installation.html Configure your root build.gradle file to include the GitHub Packages Maven repository. This step requires your GitHub credentials for authentication. ```groovy allprojects { repositories { maven { val properties = Properties() val file = File("local.properties") if (file.exists()) { properties.load(file.reader()) } name = "GitHubPackages" url = uri("https://maven.pkg.github.com/fysiki/workoutkit-android-sdk") credentials { username = properties.getProperty("GithubUser") password = properties.getProperty("GithubToken") } } } } ``` -------------------------------- ### Configure WorkoutKit Apollo Client Provider Source: https://workoutkit.fizzup.com/web/usage.html Set up the Apollo Client instance targeting the WorkoutKit GraphQL endpoint and provide it to your React application. If your endpoint requires authentication, add the authorization header here. ```tsx import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client' import { ApolloProvider } from '@apollo/client/react' import type { ReactNode } from 'react' export const WORKOUTKIT_BASE_URL = import.meta.env.VITE_WORKOUTKIT_BASE_URL const WORKOUTKIT_GRAPHQL_ENDPOINT = `${WORKOUTKIT_BASE_URL}/graphql` const client = new ApolloClient({ link: new HttpLink({ uri: WORKOUTKIT_GRAPHQL_ENDPOINT, }), cache: new InMemoryCache(), }) type WorkoutKitGraphQLProviderProps = { children: ReactNode } export function WorkoutKitGraphQLProvider({ children }: WorkoutKitGraphQLProviderProps) { return {children} } ``` -------------------------------- ### Handle Async Save in Video Controller Subclass Source: https://workoutkit.fizzup.com/ios/guides/video-workouts.html Subclass `GoVideoController` to handle asynchronous saving of workout sessions. Replace the placeholder `DispatchQueue.main.asyncAfter` with your actual backend persistence logic. ```swift final class MonVideoGoController: GoVideoController { private var savePublisher: AnyPublisher? override func saveSession(state: SaveWorkoutState) { super.saveSession(state: state) savePublisher = Future { promise in // Replace with your backend persistence. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { promise(.success(())) } }.eraseToAnyPublisher() } } ```