> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beyondwords.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Segment detection

BeyondWords can usually detect content segments on your page automatically. When segment detection is working correctly, the following player features can be enabled in your project (**Distribution → Player → Settings**) without any additional integration:

* **Highlight paragraphs**: Highlight the paragraph currently being read aloud, helping users follow along with the audio
* **Highlight words**: Highlight individual words as they are spoken, creating an immersion reading experience
* **Playback from paragraphs**: Allow users to click or tap a paragraph to begin playback from that point

In some cases, however, the structure of your website or app may prevent the player from detecting segments correctly. The following sections explain how to implement segment detection manually for JavaScript, iOS, and Android.

## JavaScript

If you're using the JavaScript player and segment detection isn't working properly, you can add markers to elements on your page to improve detection accuracy:

```html theme={null}
<h1 data-beyondwords-marker="1af51b2a-72df-4b86-bb7c-87d057231ca0">
  This is the title.
</h1>

<p data-beyondwords-marker="5d2c6eba-f612-45c7-b987-00fde473d867">
  This is the first paragraph.
</p>

<p data-beyondwords-marker="d89257cd-ff53-476e-aef2-84dadcca1cc5">
  This is the second paragraph.
</p>
```

### Markers

If you add markers manually, we recommend using randomly generated UUIDs. Markers must be stable and should not change between page refreshes.

* **If you're using the client-side integration**, markers will be automatically retrieved from your page when content is processed
* **If you're sending HTML to the BeyondWords API**, markers will be automatically extracted from the HTML when content is processed
* **If you're sending plaintext to the BeyondWords API**, you will need to set the marker attribute on each segment alongside the text

If a segment marker is not provided, BeyondWords will generate one for you. You can retrieve these from the [Get content](/api-reference/content/show) endpoint (use `?segments=full`) and add them to the HTML of your article.

We recommend generating UUIDs as markers to avoid duplicates, in case there are multiple players on the same page.

### How it works

Once the player script has loaded, it adds global listeners to your page to detect click and mousemove events.

When a user hovers over or clicks on an element, the player attempts to match that element against segments using markers (see above), xpath, or an MD5 fingerprint of the text content.

If a match is found, the player emits `HoveredSegmentUpdated` and `PressedSegment` events. Additionally, when the `currentTime` of the media updates (e.g., during playback), the player emits a `CurrentSegmentUpdated` event.

These events are used to highlight segments on the page and control playback—for example, by setting `currentTime` to the `startTime` of the segment the user clicked on. The `currentSegment` and `hoveredSegment` properties of the player are also updated accordingly.

To highlight segments, the player wraps the segment content in a `<mark>` element with custom styles. The mark is removed once highlighting ends.

To avoid interfering with your page, highlighting and click handling are disabled when hovering over a link or an element with a `click` or `mousedown` handler. Note that this does not apply to event listeners (see below).

### Event listeners

The player cannot detect event listeners registered on elements within a segment. For example, the button below does not have an `onclick` property, so playback will be affected when it is clicked:

```html theme={null}
<p data-beyondwords-marker="5d2c6eba-f612-45c7-b987-00fde473d867">
  This is the first paragraph. <button id="my-button"></button>
</p>

<script>
  document.getElementById("my-button").addEventListener("click", event => {
    console.log("The button was clicked.");
  });
</script>
```

To prevent this, call `event.preventDefault()` at the top of the event listener:

```html theme={null}
<script>
  document.getElementById("my-button").addEventListener("click", event => {
    event.preventDefault();
    console.log("The button was clicked.");
  });
</script>
```

This will prevent the player from changing its current time when the button is clicked.

### Configuration

Playback from paragraphs can be configured using the following player properties:

| Property                | Description                                               |
| ----------------------- | --------------------------------------------------------- |
| `highlightColor`        | Set a custom highlight color for segments                 |
| `highlightSections`     | Control which segments highlighting applies to            |
| `clickableSections`     | Control which segments can be clicked on                  |
| `segmentWidgetSections` | Control which segments the widget appears next to         |
| `segmentWidgetPosition` | Control which side the widget appears next to the segment |
| `currentSegment`        | Get the current segment (read-only)                       |
| `hoveredSegment`        | Get the hovered segment (read-only)                       |

## Mobile SDKs

The mobile SDK implementations are based on the JavaScript version above. Unlike the JavaScript player, the mobile SDKs cannot automatically identify segments—you will need to manually link each text segment to its BeyondWords marker.

<Tabs>
  <Tab title="Android">
    You can find a full example of playback from paragraphs integration in the Android GitHub repository:

    * [PlaybackFromSegmentsActivity.kt](https://github.com/beyondwords-io/player-android/tree/main/example/app/src/main/kotlin/io/beyondwords/example/PlaybackFromSegmentsActivity.kt)
    * [PlaybackFromSegmentsRecyclerActivity.kt](https://github.com/beyondwords-io/player-android/tree/main/example/app/src/main/kotlin/io/beyondwords/example/PlaybackFromSegmentsRecyclerActivity.kt)

    ### Highlighting the current segment

    Listen for the `CurrentSegmentUpdated` event, then find the corresponding UI element and apply your desired styling:

    ```kotlin theme={null}
    object : EventListener {
        override fun onEvent(event: PlayerEvent, settings: PlayerSettings) {
            if (event.type == "CurrentSegmentUpdated") {
                val text = segments[settings.currentSegment?.marker]
                for (i in 0 until contentView.childCount) {
                    val view = contentView.getChildAt(i)
                    if (view !is TextView) continue
                    if (view.text == text) {
                        view.setBackgroundColor(android.graphics.Color.LTGRAY)
                    } else {
                        view.setBackgroundColor(android.graphics.Color.TRANSPARENT)
                    }
                }
            }
        }
    }
    ```

    ### Handling segment clicks

    Set a `View.OnClickListener` and call `setCurrentSegment` with the corresponding marker:

    ```kotlin theme={null}
    fun onSegmentClick(segmentText: TextView) {
        val marker = segments.entries.firstOrNull { it.value == segmentText.text }?.key ?: return
        playerView.setCurrentSegment(segmentMarker = marker)
    }
    ```
  </Tab>

  <Tab title="iOS">
    You can find a full example of segments playback integration in the iOS GitHub repository:

    * [PlaybackFromSegmentsViewController.swift](https://github.com/beyondwords-io/player-ios/blob/main/Example/Example/PlaybackFromSegmentsViewController.swift)

    ### Highlighting the current segment

    Listen for the `CurrentSegmentUpdated` event, then find the corresponding UI element and apply your desired styling:

    ```swift theme={null}
    extension PlaybackFromSegmentsViewController : PlayerDelegate {
        public func player(_ playerView: PlayerView, onEvent event: PlayerEvent, settings: PlayerSettings) {
            if (self.playerView !== playerView) { return }

            if (event.type == "CurrentSegmentUpdated") {
                let text = settings.currentSegment?.marker.flatMap { self.segments[$0] }
                for view in self.contentView.arrangedSubviews {
                    guard let label = view as? UILabel else { continue }
                    if (label.text == text) {
                        label.backgroundColor = .lightGray
                    } else {
                        label.backgroundColor = .clear
                    }
                }
            }
        }
    }
    ```

    ### Handling segment taps

    Set a `UITapGestureRecognizer` and call `setCurrentSegment` with the corresponding marker:

    ```swift theme={null}
    @objc private func segmentTapped(_ gesture: UITapGestureRecognizer) {
        guard let label = gesture.view as? UILabel else { return }
        guard let marker = self.segments.first(where: { $0.value == label.text })?.key else { return }
        playerView.setCurrentSegment(segmentMarker: marker)
    }
    ```
  </Tab>
</Tabs>
