> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://fastpix.com/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://fastpix.com/docs/_mcp/server.

# Switch subtitle tracks

> Learn how to detect, switch, and render subtitle tracks in the FastPix iOS Player.

Learn how to detect, switch, and render subtitle tracks in the FastPix iOS Player.

The FastPix iOS Player SDK supports WebVTT-based subtitle tracks. It automatically parses the HLS manifest, fetches subtitle segments, and delivers cues in sync with playback. Your app is responsible for rendering the subtitle text in the UI.

## Set up the subtitle track delegate

```swift
playerViewController.subtitleTrackDelegate = self
```

## Set a preferred subtitle track

Set a preferred subtitle track by language name. The SDK automatically selects it when the video loads.

```swift
// Pass the display name of the language (case-insensitive)
playerViewController.setPreferredSubtitleTrack("Hindi")
```

The preferred track is automatically applied on every playlist item change.

## Get available subtitle tracks

```swift
let subtitleTracks = playerViewController.getSubtitleTracks()
```

## Get the current subtitle track

```swift
// Returns nil if subtitles are disabled
let currentTrack = playerViewController.getCurrentSubtitleTrack()
```

## Switch subtitle tracks

```swift
// Switch by track ID
try? playerViewController.setSubtitleTrack(trackId: track.id)
```

## Disable subtitles

```swift
playerViewController.disableSubtitles()
```

## Render subtitle cues

The SDK delivers subtitle text in real time through the `onSubtitleCueChange` callback. Create a label to display the text:

```swift
private let subtitleLabel: UILabel = {
    let label = UILabel()
    label.textColor = .white
    label.font = UIFont.systemFont(ofSize: 16, weight: .medium)
    label.textAlignment = .center
    label.numberOfLines = 0
    label.backgroundColor = UIColor.black.withAlphaComponent(0.5)
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()
```

Position the label above the seek bar inside `playerViewController.view`:

```swift
private func setupSubtitleLabel() {
    playerViewController.view.addSubview(subtitleLabel)
    playerViewController.view.bringSubviewToFront(subtitleLabel)

    NSLayoutConstraint.activate([
        subtitleLabel.leadingAnchor.constraint(
            equalTo: playerViewController.view.leadingAnchor, constant: 20),
        subtitleLabel.trailingAnchor.constraint(
            equalTo: playerViewController.view.trailingAnchor, constant: -20),
        subtitleLabel.bottomAnchor.constraint(
            equalTo: playerViewController.view.bottomAnchor, constant: -130)
    ])
}
```

## Handle subtitle events

Conform to `FastPixSubtitleTrackDelegate` to receive subtitle updates:

```swift
extension VideoPlayerViewController: FastPixSubtitleTrackDelegate {

    // Called when subtitle tracks finish loading
    func onSubtitlesLoaded(tracks: [SubtitleTrack]) {
        print("Subtitle tracks available:", tracks)
    }

    // Called when the active subtitle track changes
    func onSubtitleChange(track: SubtitleTrack?) {
        print("Subtitle switched to:", track?.label ?? "Off")
    }

    // Called every time a new subtitle cue becomes active
    func onSubtitleCueChange(information: SubtitleRenderInfo) {
        DispatchQueue.main.async {
            if information.text.isEmpty {
                self.subtitleLabel.isHidden = true
            } else {
                self.subtitleLabel.text = information.text
                self.subtitleLabel.isHidden = false
            }
        }
    }

    // Called when subtitle tracks fail to load
    func onSubtitlesLoadedFailed(error: SubtitleTrackError) {
        print("Subtitle load failed:", error)
    }
}
```

## SubtitleTrack model

| Property       | Type      | Description                                       |
| -------------- | --------- | ------------------------------------------------- |
| `id`           | `String`  | Unique identifier for the track                   |
| `languageCode` | `String`  | BCP-47 language tag (for example, `"hi"`, `"en"`) |
| `label`        | `String`  | Human-readable label shown in UI                  |
| `playlistURL`  | `String?` | Resolved URL of the subtitle playlist             |
| `isSelected`   | `Bool`    | Whether this track is currently active            |

## SubtitleRenderInfo model

| Property       | Type     | Description                                              |
| -------------- | -------- | -------------------------------------------------------- |
| `text`         | `String` | Subtitle cue text (empty string means the cue has ended) |
| `timestamp`    | `Double` | Playback time in seconds when the cue is active          |
| `languageCode` | `String` | Language code of the active subtitle track               |

> **Important:**
>
> * Subtitle rendering is the host app's responsibility. The SDK delivers cue text only.
> * Call `disableSubtitles()` when switching playlist items to prevent stale cues from appearing on videos without subtitles.
> * Add the subtitle label to `playerViewController.view`, not `self.view`, to ensure correct positioning across orientations and full-screen transitions.