# Testing & Simulation (videoURL)

**How to test the integration without physically performing the exercises.**

**Applies to: Workout player (Main, Workout, Plan, Personalized Plan, Custom Workout), Camera, Assessments.** Not supported by the games (Balloon Pop, Color Chase, Alien Squat Shooter) — they always use the live camera.

| Parameter | Type | Default | Applies to | What it does internally |
|-----------|------|---------|------------|-------------------------|
| videoURL | string | — | Workout player, Camera, Assessments | Replaces the live camera stream as the motion-tracking input. Instead of opening the device camera (`getUserMedia`), the SDK sets the provided URL as the source of its internal `<video>` element and runs the full MediaPipe pose-tracking pipeline on that video — rep counting, form analysis, accuracy scoring, and statistics all work exactly as if a real person were moving in front of the camera |

**Behavior details:**
- The video **loops continuously** until the session ends — it never stops on its own, so reps keep counting for as long as the exercise runs.
- The video is loaded with `crossOrigin="anonymous"`, so the URL must be **CORS-accessible** (served with `Access-Control-Allow-Origin`), otherwise landmark extraction fails.
- Pose processing runs on the main thread when `videoURL` is set (the web-worker fast path is only used for the live camera). This is intentional and does not change results.
- No camera permission is requested for the video-driven pipeline itself.
- The video should show one fully visible person performing the target exercise, filmed like a normal front-facing camera feed. You can use the exercise's own demo video from the [Content API](/docs/content-api) (`video_URL` field) as a ready-made input.

**Recommended testing recipe:**
1. Pass `videoURL` pointing at a recording of the exercise being performed.
2. Pass `shouldSendStats: true` if you want the simulated session saved to the backend ([Session & Data Saving](/docs/customization-parameters/session-data)) so you can verify it via the Workout Sessions API.
3. Optionally add `showSilhouette: false` to skip the camera-positioning (silhouette) screen, or `immediateShowSkip: true` to show its Skip button instantly.
4. Optionally use `start_from_exercise` (with `completed_exercises` and `start_from_rest: true`) to jump to a later part of the workout ([Workout Configuration](/docs/customization-parameters/workout-configuration)).

**When NOT to use `videoURL`:** if you only need to click through screens without any tracking data, `motionTrackingEnabled: false` (see [Motion Tracking Settings](/docs/customization-parameters/motion-tracking-settings)) converts exercises to auto-advancing timers — but then **no reps are counted and no accuracy data is produced**. Use `videoURL` when you need realistic tracking data without a person.

**Simulate a workout with a prerecorded video**

_Swift (iOS)_
```swift
// Via customParams — full tracking pipeline runs on the video
kinestex.createWorkoutView(
    workout: "Fitness Lite",
    user: user,
    customParams: [
        "videoURL": "https://cdn.yourapp.com/test/squats-demo.mp4",
        "shouldSendStats": true // save the simulated session
    ],
    isLoading: $isLoading,
    onMessageReceived: { /* ... */ }
)
```

_Kotlin (Android)_
```kotlin
// Via customParams — full tracking pipeline runs on the video
KinesteXSDK.createWorkoutView(
    context = this,
    workoutName = "Fitness Lite",
    customParams = mutableMapOf(
        "videoURL" to "https://cdn.yourapp.com/test/squats-demo.mp4",
        "shouldSendStats" to true // save the simulated session
    ),
    isLoading = viewModel.isLoading,
    onMessageReceived = { message -> handleWebViewMessage(message) },
    permissionHandler = this
)
```

_React Native_
```jsx
// Via customParameters — full tracking pipeline runs on the video
const postData: IPostData = {
  key: 'YOUR_API_KEY',
  userId: 'test-user-1',
  company: 'YOUR_COMPANY',
  customParameters: {
    videoURL: 'https://cdn.yourapp.com/test/squats-demo.mp4',
    shouldSendStats: true, // save the simulated session
  },
};
```

_Flutter_
```dart
// Via customParams — full tracking pipeline runs on the video
KinesteXAIFramework.createWorkoutView(
  workoutName: "Fitness Lite",
  isShowKinestex: showKinesteX,
  isLoading: ValueNotifier<bool>(false),
  customParams: {
    "videoURL": "https://cdn.yourapp.com/test/squats-demo.mp4",
    "shouldSendStats": true, // save the simulated session
  },
  onMessageReceived: (message) { handleWebViewMessage(message); },
);
```

_HTML / JavaScript_
```html
// Direct in postData object — full tracking pipeline runs on the video
const postData = {
  userId: "test-user-1",
  company: "YOUR_COMPANY",
  key: "YOUR_API_KEY",
  videoURL: "https://cdn.yourapp.com/test/squats-demo.mp4",
  shouldSendStats: true, // save the simulated session
};
```

_React (TypeScript)_
```tsx
// Via customParameters — full tracking pipeline runs on the video
const postData: IPostData = {
  key: 'YOUR_API_KEY',
  userId: 'test-user-1',
  company: 'YOUR_COMPANY',
  customParameters: {
    videoURL: 'https://cdn.yourapp.com/test/squats-demo.mp4',
    shouldSendStats: true, // save the simulated session
  },
};
```

---
Source: https://www.kinestex.com/docs/customization-parameters/testing-simulation · Index: https://www.kinestex.com/llms.txt
