Select platform: [HTML5](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/html5/bookmarks.md.txt "View this page for the HTML5 platform docs.") [Android](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/android/bookmarks.md.txt "View this page for the Android platform docs.") [iOS](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/ios/bookmarks.md.txt "View this page for the iOS platform docs.") [tvOS](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/tvos/bookmarks.md.txt "View this page for the tvOS platform docs.") [Roku](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/roku/bookmarks.md.txt "View this page for the Roku platform docs.")

<br />

This guide shows how to implement bookmarking using the IMA DAI SDK
when using Dynamic Ad Insertion (DAI) for video-on-demand (VOD) streams.
This assumes a working IMA DAI implementation, such as the one presented in


[Get Started](https://developers.google.com/interactive-media-ads/docs/sdks/ios/dai-quickstart).


## What is bookmarking?

Bookmarking is the ability to save and then return to a specific point
in the content stream. Suppose a user watches five minutes of content,
leaves the video stream, and then returns to it. Bookmarking saves the
user's position in the stream so the stream can pick up from where it
left off, providing a seamless experience to the viewer.

## DAI bookmarking under the hood

When bookmarking a DAI stream, you must record the stream id and time
when the user leaves the video. When the user returns, re-request the
stream and seek to the saved time. Since each instance of the requested
stream can have ad breaks of different durations simply saving the stream
time won't work. What you really want to do is continue from the same
**content time**.

## Conversion methods to the rescue

The IMA DAI SDK provides a pair of methods to request the **content time**
for a given **stream time** and the **stream time** for a given **content
time** . Using these conversion methods you can store the bookmarked
**content time** and then seek to the corresponding **stream time** in
the new instance of the stream. Here's the approach, including a link
to a sample app that shows a working bookmarking implementation.

## Saving bookmarks

Save a bookmark when the Activity is paused.

### Objective-C

```objective-c
- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  [self.contentPlayer pause];
  // Ignore this if we're presenting a modal view (e.g. in-app clickthrough).
  if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) {
    // Don't save bookmark if we're playing a live stream.
    if (self.video.streamType != StreamTypeLive) {
      NSTimeInterval contentTime = [self.streamManager
          contentTimeForStreamTime:CMTimeGetSeconds(self.contentPlayer.currentTime)];
      [self.delegate videoViewController:self didReportSavedTime:contentTime forVideo:self.video];
    }
```

### Swift

```swift
override func viewWillDisappear(_ animated: Bool) {
  super.viewWillDisappear(animated)
  contentPlayer.pause()
  if isMovingFromParent {
    // Only save bookmark if we're playing a VOD stream.
    if let vodStream = stream as? VODStream, let streamManager = streamManager {
      let contentTime = streamManager.contentTime(
        forStreamTime: contentPlayer.currentTime().seconds)
      if contentTime.isFinite, contentTime > 0 {
        delegate?.videoViewController(self, didReportBookmarkedTime: contentTime, for: vodStream)
      }
    }
    if trackingContent {
      removeContentPlayerObservers()
    }
    streamManager?.destroy()
    adsLoader?.contentComplete()
    streamManager = nil
    adsLoader = nil
  }
}
```

## Loading bookmarks

Load the bookmark when re-requesting a stream. It's part of implementing
the `VideoStreamPlayer` interface.

### Objective-C

```objective-c
case kIMAAdEvent_STREAM_LOADED: {
  if (self.video.streamType == StreamTypeVOD) {
    [self addContentPlayerObservers];
    if (self.video.savedTime > 0) {
      NSTimeInterval streamTime =
          [self.streamManager streamTimeForContentTime:self.video.savedTime];
      [self.IMAVideoDisplay seekStreamToTime:streamTime];
      self.video.savedTime = 0;
    }
  }
```

### Swift

```swift
case .STREAM_LOADED:
  guard let stream else { return }
  addContentPlayerObservers()
  if let vodStream = stream as? VODStream, vodStream.bookmarkTime > 0 {
    bookmarkStreamTime = streamManager.streamTime(forContentTime: vodStream.bookmarkTime)
    if let time = bookmarkStreamTime {
      pendingBookmarkSeek = true
      logMessage(
        "STREAM_LOADED: Bookmark pending for contentTime: \(String(format: "%.2f", vodStream.bookmarkTime)) (streamTime: \(String(format: "%.2f", time)))"
      )
      vodStream.bookmarkTime = 0
    }
  }
```

## Sample app

[Sample app](https://github.com/googleads/googleads-ima-ios-dai)