The Bazaarvoice Mobile SDKs provide access to most of the core products Bazaarvoice offers. To learn more, go to the Mobile SDK documentation home page.

Contents

(+ show- hide)

This documentation explains how consumer-generated content (CGC), including reviews and statistics, as well as product information can be displayed using the mobile SDK.

Introduction

Use the Bazaarvoice Mobile SDKs to enable Conversations functionality, such as Ratings and Reviews. The Conversations module provides an easy-to-use wrapper around the Conversations API. The mobile SDK support the following Conversations display features:

You will need your apiKeyConversations to implement and use Conversations with Mobile SDKs.

The completed project for this code walkthrough for Swift and Objective-C is in the SDK path /Examples/Conversations. For a more comprehensive demonstration of the Conversations SDK, please also see the BVSDKDemo project under /Examples/BVSDKDemo.

Before you start implementing this Mobile SDK module, verify your installation by checking the steps on the Installation page.

Displaying content

Displaying content is centered around the idea of a Product Display Page. For example, the following example page is populated using a single ProductDisplayPageRequest, and shown inside of a BVProductDisplayPageViewController.

We're showing very common pieces of content here: average rating, number of reviews, and number of questions/answers. After showing the Product Display Page, you can paginate through more Reviews and Question/Answers (discussed below). Lastly, you can load Bulk Ratings for multiple products at a time, which is useful when showing stars and number of reviews on a category page.

Content types

The tabs below describe the available content types in more detail.

Loading a product display page

When showing a product display page, use a BVProductDisplayPageRequest to fetch useful data like reviewStatistics or to include the first 10 BVReview reviews. Then, display this data inside a designated BVProductDisplayPageViewController, discussed below.

First, let's look at a simple BVProductDisplayPageRequest

// request product information, including statistics on reviews and questions/answers.
let request = BVProductDisplayPageRequest(productId: "test1")
                .includeStatistics(.Reviews)
                .includeStatistics(.Questions)
// request product information, including statistics on reviews and questions/answers.
BVProductDisplayPageRequest* request = [[BVProductDisplayPageRequest alloc] initWithProductId:@"test1"];

[request includeStatistics:PDPContentTypeReviews];
[request includeStatistics:PDPContentTypeQuestions];

In the code above, a ProductDisplayPageRequest is created for productId test1. We also include statistics for reviews and questions/answers. You may want to include some actual content with it, as shown below. We also sort the included reviews by their submissionTime.

// request product information, including the first 5 questions and 10 reviews, sorted by their submissionTime.
let request = BVProductDisplayPageRequest(productId: "test1")
                .includeContent(.Reviews, limit: 10)
                .includeContent(.Questions, limit: 5)
                .sortIncludedReviews(.SubmissionTime, order: .Descending)
// request product information, including statistics on reviews and questions/answers.
BVProductDisplayPageRequest* request = [[BVProductDisplayPageRequest alloc] initWithProductId:@"test1"];

[request includeContent:PDPContentTypeReviews limit:10];
[request includeContent:PDPContentTypeQuestions limit:5];
[request sortIncludedReviews:BVSortOptionReviewsSubmissionTime order:BVSortOrderDescending];

Let's load this request!

To do so, simply call the load function on the request object, and use the success and failure blocks appropriately.

// load the data
request.load({ (response: BVProductsResponse) in

    if let product = response.result {

        product.reviewStatistics?.averageOverallRating // number of stars: 4.1
        product.reviewStatistics?.totalReviewCount     // number of reviews: 8

        product.qaStatistics?.totalQuestionCount       // number of questions: 2
        product.qaStatistics?.totalAnswerCount         // number of answers: 4

    }

}) { (errors:[NSError]) in
    // handle failure appropriately
}
// load the data
[request load:^(BVProductsResponse * _Nonnull response) {

    BVProduct* product = response.result;

    if (product) {

        product.reviewStatistics.averageOverallRating; // number of stars: 4.1
        product.reviewStatistics.totalReviewCount;     // number of stars: 4.1

        product.qaStatistics.totalQuestionCount;       // number of questions: 2
        product.qaStatistics.totalAnswerCount;         // number of answers: 4

    }

} failure:^(NSArray * _Nonnull errors) {
    // handle failure appropriately
}];
Displaying a product display page

Use a BVProductDisplayPageViewController, BVProductDisplayPageTableViewController, or BVProductDisplayPageCollectionViewController to display this content.

  • Create a new Cocoa Touch Class called ProductDisplayViewController and make it subclass BVProductDisplayPageViewController:

    And import BVSDK from ProductDisplayViewController.

  • Now, modify viewDidLoad to load a ProductDisplayPageRequest and set self.product when loaded:

    import BVSDK
    
    class ProductPageViewController: BVProductDisplayPageViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // load product display information for product "test1"
            let request = BVProductDisplayPageRequest(productId: "test1")
    
            request.load({ (response: BVProductsResponse) in
    
                // tell 'BVProductDisplayPageViewController' which product is being shown in this view controller
                self.product = response.result
    
            }) { (errors: [NSError]) in
                // handle error appropriately
            }
    
        }
    }
    
    @import BVSDK;
    
    @interface ProductPageViewController : BVProductDisplayPageViewController
    
    @end
    
    @implementation ProductPageViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // load product display information for product "test1"
        BVProductDisplayPageRequest* request = [[BVProductDisplayPageRequest alloc] initWithProductId:@"test1"];
    
        [request load:^(BVProductsResponse * _Nonnull response) {
    
            // tell 'BVProductDisplayPageViewController' which product is being shown in this view controller
            self.product = response.result;
    
        } failure:^(NSArray<NSError *> * _Nonnull errors) {
            // handle error appropriately
        }];
    
    }
    
    @end
    

Loading a product display page

When showing a product display page, use a BVProductQuery to fetch useful data like reviewStatistics or to include the first 10 BVReview reviews, discussed below.

First, let's look at a simple BVProductQuery

let productQuery = BVProductQuery(productId: "test1") 
      .include(.reviews) 
      .include(.questions) 

In the code above, a ProductQuery is created for productId test1. We also include statistics for reviews and questions/answers. You may want to include some actual content with it, as shown below. We also sort the included reviews by their submissionTime.

    let productQuery = BVProductQuery(productId: "test1")
        .include(.reviews, limit: 10)
        .include(.questions, limit: 5)
        .sort(.reviews(.submissionTime), order: .descending)

Let's load this request!

To do so, add a handler and use the success and failure cases and call the async method on the productQuery object.

productQuery.handler {
        (response: BVConversationsQueryResponse < BVProduct > ) in
        if
        case .failure(let error) = response {
            // handle failure appropriately 
            return
        }
        guard
        case let.success(_, products) = response
        else {
            return
        }
        if let product = products.first {
            product.reviewStatistics ? .averageOverallRating // number of stars: 4.1 
            product.reviewStatistics ? .totalReviewCount // number of reviews: 8 
            product.qaStatistics ? .totalQuestionCount // number of questions: 2 
            product.qaStatistics ? .totalAnswerCount // number of answers: 4 
        }
    }
    .configure(configuration)
productQuery.async(urlSession: URLSession(configuration: .default))

Loading more reviews

As shown previously, you should use a ProductDisplayPageRequest to load the first page of CGC that your users will see (up 20 reviews). When loading reviews, you should request and display reviews in a BVReviewsCollectionView or BVReviewsTableView container. Reviews can also include Products and Comments.

// Add a BVReviewsTableView to your UIViewController and connect the outlet.
@IBOutlet weak var reviewsTableView : BVReviewsTableView!
var reviews : [BVReview] = []
...

// Now load the reviews from the BVReviewsTableView.
// request 10 reviews, starting at index 20
let reviewsRequest = BVReviewsRequest(productId: "test1", limit: 10, offset: 20)

// Add in other options for includes, filters, and sorts on the reviewsRequest object

reviewsTableView.load(reviewsRequest, success: { (response) in

    self.reviews = response.results
    self.reviewsTableView.reloadData()

    }) { (error) in

    print(error)

}
// Add a BVReviewsTableView to your UIViewController and connect the outlet.
@property (weak, nonatomic) IBOutlet BVReviewsTableView *reviewsTableView;
@property NSArray *reviews;
...

// Now load the reviews from the BVReviewsTableView.
// request 10 reviews, starting at index 20
BVReviewsRequest* request = [[BVReviewsRequest alloc] initWithProductId:@"test1" limit:10 offset:20];

// Add in other options for includes, filters, and sorts on the reviewsRequest object

[self.reviewsTableView load:request success:^(BVReviewsResponse * _Nonnull response) {
    self.reviews = response.results;
    [self.reviewsTableView reloadData];
} failure:^(NSArray * _Nonnull errors) {
    NSLog(@"Error loading reviews");
}];

A BVReviewsRequest requires three parameters:

  • productId - the productId that you want reviews for
  • limit - max number of reviews to fetch (maximum of 20)
  • offset - the index to start on

A combination of limit and offset should be used to load more pages of reviews upon the user's request.

You can add filters and sorts to the request, as shown below:

// request 10 reviews that have photos, starting at index 0, sorted by overall rating.
let request = BVReviewsRequest(productId: "test1", limit: 10, offset: 0)
                .addFilter(.HasPhotos, filterOperator: .EqualTo, value: "true")
                .addReviewSort(.Rating, order: .Ascending)
// request 10 reviews that have photos, starting at index 0, sorted by overall rating.
BVReviewsRequest* request = [[BVReviewsRequest alloc] initWithProductId:@"test1" limit:10 offset:20];

[request addFilter:BVReviewFilterTypeHasPhotos filterOperator:BVFilterOperatorEqualTo value:@"true"]
[request addReviewSort:BVSortOptionReviewsSubmissionTime order:BVSortOrderDescending];

Similarly to the ProductDisplayPageRequest, loading reviews is simply done by calling the load() method on the BVReviewsCollectionViewor BVReviewsTableView container as shown above.

Displaying reviews

Multiple reviews should be shown in one of the following container view:

  • BVReviewView
  • BVReviewsTableView
  • BVReviewsCollectionView

Each review should be shown using one of the following views:

  • BVReviewView
  • BVReviewTableViewCell
  • BVReviewCollectionViewCell

Let's create a UIViewController that holds a BVReviewsTableView and display 10 reviews in it using BVReviewTableViewCell.

  • Create a new Cocoa Touch Class called DemoReviewViewController and make it subclass UIViewController:

  • Import BVSDK from DemoReviewViewController, and add an instance of BVReviewsTableView.

    import UIKit
    import BVSDK
    
    class DemoReviewsViewController: UIViewController {
    
        @IBOutlet weak var tableView : BVReviewsTableView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
    }
    
    @import BVSDK;
    
    @interface DemoReviewsViewController()
    
    @property (nonatomic, weak) IBOutlet BVReviewsTableView *tableView;
    
    @end
    
    // ...
    
    @implementation DemoReviewsViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    }
    
    @end
    
  • In DemoReviewViewController.xib, add a UITableView to your view and add appropriate constraints. Change its class to BVReviewsTableView, and hook it up to your IBOutlet:

  • Create a subclass of UITableViewCell named DemoReviewTableViewCell:

  • Change the type of DemoReviewTableViewCell to BVReviewTableViewCell and add appropriate UI elements. In the code below you can override the review property to update the UI elements:

    import UIKit
    import BVSDK
    
    class DemoReviewTableViewCell: BVReviewTableViewCell {
    
        @IBOutlet weak var reviewTitle : UILabel!
        @IBOutlet weak var reviewText : UILabel!
    
        override var review: BVReview! {
            didSet {
                reviewTitle.text = review.title
                reviewText.text = review.reviewText
            }
        }
    
    }
    
    @import BVSDK;
    
    @interface DemoReviewTableViewCell : BVReviewTableViewCell
    
    @property (nonatomic, weak) IBOutlet UILabel *reviewTitle;
    @property (nonatomic, weak) IBOutlet UILabel *reviewText;
    
    @end
    
    // ...
    
    @implementation DemoReviewTableViewCell
    
    -(void)setReview:(BVReview *)review {
        [super setReview:review];
    
        self.reviewTitle.text = review.title;
        self.reviewText.text = review.reviewText;
    }
    
    @end
    
  • Add your reviewText and reviewTitle UILabels to DemoReviewTableViewCell.xib, and hook up your outlets:

  • Finally, inside DemoReviewViewController, use a BVReviewsRequest object to load 10 reviews. Use instances of DemoReviewTableViewCell to display:

    import UIKit
    import BVSDK
    
    class DemoReviewsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        @IBOutlet weak var tableView : BVReviewsTableView!
        var reviews : [BVReview] = []
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.tableView.delegate = self
            self.tableView.dataSource = self
            self.tableView.registerNib(UINib(nibName: "DemoReviewTableViewCell", bundle: nil), forCellReuseIdentifier: "DemoReviewTableViewCell")
    
            let request = BVReviewsRequest(productId: "test1", limit: 10, offset: 20)
            self.tableView.load({ (response: BVReviewsResponse) in
    
                self.reviews = response.results
                self.tableView.reloadData()
    
            }) { (errors: [NSError]) in
                // handle failure appropriately
            }
    
        }
    
        func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return self.reviews.count
        }
    
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
            let cell = tableView.dequeueReusableCellWithIdentifier("DemoReviewTableViewCell") as! DemoReviewTableViewCell
    
            cell.review = self.reviews[indexPath.row]
    
            return cell
    
        }
    
    }
    
    @import BVSDK;
    
    @interface DemoReviewsViewController : UIViewController
    
    @property (nonatomic, weak) IBOutlet BVReviewsTableView *tableView;
    @property (nonatomic, strong) NSArray* reviews;
    
    @end
    
    // ...
    
    @implementation DemoReviewsViewController
    
    -(void)viewDidLoad {
        [super viewDidLoad];
    
        self.tableView.delegate = self;
        self.tableView.dataSource = self;
        [self.tableView registerNib:[UINib nibWithNibName:@"DemoReviewTableViewCell" bundle:nil] forCellReuseIdentifier:@"DemoReviewTableViewCell"];
    
        BVReviewsRequest* request = [[BVReviewsRequest alloc] initWithProductId:@"test1" limit:10 offset:20];
        [self.tableView load:^(BVReviewsResponse * _Nonnull response) {
    
            self.reviews = response.results;
            [self.tableView reloadData];
    
        } failure:^(NSArray * _Nonnull errors) {
            // handle failure appropriately
        }];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return [self.reviews count];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        DemoReviewTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"DemoReviewTableViewCell"];
    
        cell.review = [self.reviews objectAtIndex:indexPath.row];
    
        return cell;
    
    }
    
    @end
    
      let reviewQuery = BVReviewQuery(productId: "test1", limit: 10, offset: 20)
          .configure(configuration)
          .handler {
              (response: BVConversationsQueryResponse < BVReview > ) in
              if
              case .failure(let error) = response {
                  // error 
                  return
              }
              guard
              case let.success(_, reviews) = response
              else {
                  return
              }
              // success 
          }
      // Add in other options for includes, filters, and sorts on the reviewsRequest object 
      guard
      let req = reviewQuery.request
      else {
          return
      }
      reviewQuery.async()
  

Loading Questions & Answers

Similarly to reviews, you should use a ProductDisplayPageRequest to load the first page of Questions/Answers (up the first 20 questions). When loading questions, you should request and display questions in a BVQuestionsCollectionView or BVQuestionsTableView container::

// Add a BVQuestionsTableView to your UIViewController and connect the outlet.
@IBOutlet weak var questionsTableView : BVQuestionsTableView!
var questions : [BVQuestion] = []
...

// Now load the questions from the BVQuestionsTableView.
// request 10 questions, starting at index 20
let questionsRequest = BVQuestionsRequest(productId: "test1", limit: 10, offset: 20)

questionsTableView.load(questionsRequest, success: { (response) in

            self.questions = response.results
            self.questionsTableView.reloadData()

            }) { (error) in

            print(error)

        }
// Add a BVQuestionsTableView to your UIViewController and connect the outlet.
@property (weak, nonatomic) IBOutlet BVQuestionsTableView *questionsTableView;
@property NSArray *questions;
...

// Now load the questions from the BVQuestionsTableView.
// request 10 questions, starting at index 20
BVQuestionsRequest* request = [[BVQuestionsRequest alloc] initWithProductId:@"test1" limit:10 offset:20];
[self.questionsTableView load:request success:^(BVQuestionsResponse * _Nonnull response) {
    self.questions = response.results;
    [self.questionsTableView reloadData];
} failure:^(NSArray * _Nonnull errors) {
    NSLog(@"Error loading questions");
}];

A QuestionsAndAnswersRequest requires the same three parameters as BVQuestionsRequest:

  • productId - the productId that you want questions for
  • limit - max number of questions to fetch (maximum of 20)
  • offset - the index to start on

A combination of limit and offset should be used to load more pages of quesitons upon the user's request.

You can add filters and sorts to the request, as shown below:

// request 10 questions that have answers, starting at index 0, sorted by the number of answers each question has.
let request = BVQuestionsAndAnswersRequest(productId: "test1", limit: 10, offset: 20)
                    .addFilter(.HasAnswers, filterOperator: .EqualTo, value: "true")
                    .addQuestionSort(.SubmissionTime, order: .Ascending)
// request 10 questions that have answers, starting at index 0, sorted by the number of answers each question has.
BVQuestionsAndAnswersRequest* request = [[BVQuestionsAndAnswersRequest alloc] initWithProductId:@"test1" limit:10 offset:0];
[request addFilter:BVQuestionFilterTypeHasAnswers filterOperator:BVFilterOperatorEqualTo value:@"true"];
[request addQuestionSort:BVSortOptionQuestionsLastModeratedTime order:BVSortOrderDescending];

Displaying Questions & Answers

Questions & Answers should be shown in one of the following container view:

  • BVQuestionsView
  • BVQuestionsTableView
  • BVQuestionsCollectionView
  • BVAnswersView
  • BVAnswersTableView
  • BVAnswersCollectionView

Each question/answer should be shown using one of the following views:

  • BVQuestionView
  • BVQuestionTableViewCell
  • BVQuestionCollectionViewCell
  • BVAnswerView
  • BVAnswerTableViewCell
  • BVAnswerCollectionViewCell

Let's create a UIViewController that holds a BVQuestionTableView and display 10 questions in it using BVQuestionTableViewCells.

  • Create a new Cocoa Touch Class called DemoQuestionViewController and make it subclass UIViewController:

  • Import BVSDK from DemoQuestionViewController, and add an instance of BVQuestionsTableView.

    import UIKit
    import BVSDK
    
    class DemoQuestionViewController: UIViewController {
    
        @IBOutlet weak var questionsTableView : BVQuestionsTableView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    }
    
    @import BVSDK;
    
    @interface DemoQuestionsViewController()
    
    @property (nonatomic, weak) IBOutlet BVQuestionsTableView *tableView;
    
    @end
    
    // ...
    
    @implementation DemoQuestionsViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    }
    
    @end
    
  • In DemoQuestionViewController.xib, add a UITableView to your view and add appropriate constraints. Change its class to BVQuestionsTableView, and hook it up to your IBOutlet:

  • Create a subclass of UITableViewCell named DemoQuestionTableViewCell:

  • Change the type of DemoQuestionTableViewCell to BVQuestionTableViewCell and add appropriate UI elements. In the code below you can override the question property to update the UI elements:

    import UIKit
    import BVSDK
    
    class DemoQuestionTableViewCell: BVQuestionTableViewCell {
    
        @IBOutlet weak var questionSummary : UILabel!
        @IBOutlet weak var questionDetails : UILabel!
    
        override var question: BVQuestion! {
            didSet {
                questionSummary.text = question.questionSummary
                questionDetails.text = question.questionDetails
            }
        }
    }
    
    @import BVSDK;
    
    @interface DemoQuestionTableViewCell : BVQuestionTableViewCell
    
    @property (nonatomic, weak) IBOutlet UILabel *questionSummary;
    @property (nonatomic, weak) IBOutlet UILabel *questionDetails;
    
    @end
    
    // ...
    
    @implementation DemoQuestionTableViewCell
    
    -(void)setQuestion:(BVQuestion *)question {
        [super setQuestion:question];
    
        self.questionSummary.text = question.questionSummary;
        self.questionDetails.text = question.questionDetails;
    }
    
    @end
    
  • Add your questionSummary and questionDetails UILabels to DemoQuestionTableViewCell.xib, and hook up your outlets:

  • Finally, inside DemoQuestionViewController, use a BVQuestionsAndAnswersRequest object to load 10 questions and their associated answers. Use instances of DemoQuestionTableViewCell to display:

    Answers are not displayed in this tutorial but should be displayed alongside questions.
    import UIKit
    import BVSDK
    
    class DemoQuestionViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        @IBOutlet weak var tableView : BVQuestionsTableView!
        var questions : [BVQuestion] = []
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.tableView.delegate = self
            self.tableView.dataSource = self
            self.tableView.registerNib(UINib(nibName: "DemoQuestionTableViewCell", bundle: nil), forCellReuseIdentifier: "DemoQuestionTableViewCell")
    
            let request = BVQuestionsAndAnswersRequest(productId: "test1", limit: 10, offset: 20)
            self.tableView.load({ (response: BVQuestionsAndAnswersResponse) in
    
                self.questions = response.results
                self.tableView.reloadData()
    
            }) { (errors: [NSError]) in
                // handle failure appropriately
            }
    
        }
    
        func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return self.questions.count
        }
    
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
            let cell = tableView.dequeueReusableCellWithIdentifier("DemoQuestionTableViewCell") as! DemoQuestionTableViewCell
    
            cell.question = self.questions[indexPath.row]
    
            return cell
    
        }
    
    }
    
    @import BVSDK;
    
    @interface DemoQuestionsViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>
    
    @property (nonatomic, weak) IBOutlet BVQuestionsTableView *tableView;
    @property (nonatomic, strong) NSArray<BVQuestion*>* questions;
    
    @end
    
    // ...
    
    @implementation DemoQuestionsViewController
    
    -(void)viewDidLoad {
        [super viewDidLoad];
    
        self.tableView.delegate = self;
        self.tableView.dataSource = self;
        [self.tableView registerNib:[UINib nibWithNibName:@"DemoQuestionTableViewCell" bundle:nil] forCellReuseIdentifier:@"DemoQuestionTableViewCell"];
    
        BVQuestionsAndAnswersRequest* request = [[BVQuestionsAndAnswersRequest alloc] initWithProductId:@"test1" limit:10 offset:20];
        [self.tableView load:^(BVQuestionsAndAnswersResponse * _Nonnull response) {
    
            self.questions = response.results;
            [self.tableView reloadData];
    
        } failure:^(NSArray * _Nonnull errors) {
            // handle failure appropriately
        }];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return [self.questions count];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        DemoQuestionTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"DemoQuestionTableViewCell"];
    
        cell.question = [self.questions objectAtIndex:indexPath.row];
    
        return cell;
    
    }
    
    @end
    
        let questionQuery =
        BVQuestionQuery(productId: "test1", limit: 10, offset: 20)
        .configure(configuration)
        .handler {
            (response: BVConversationsQueryResponse < BVQuestion > ) in
            if
            case .failure(let error) = response {
                // error 
                return
            }
            guard
            case let.success(_, questions) = response
            else {
                return
            }
            // success 
        }
    guard
    let req = questionQuery.request
    else {
        return
    }
    questionQuery.async()
    

Loading review comments

Comments can be loaded either by a single comment ID, or you can load comments by a review ID with limit and offset parameters. Simply construct a BVCommentsRequest object and choose one of the default initializers provided. The examples provided below demonstrate how to fetch a list of comments from a given review ID.

let limit : UInt16  = 99
let offset : UInt16 = 0

let request = BVCommentsRequest(reviewId: "myReviewId", limit: limit, offset: offset)
// Optionally, comments can have includes, filters, and sorts added to the request.
request.addInclude(.reviews)
request.addFilter(.contentLocale, filterOperator: .equalTo, value: "en_US")
request.addCommentSort(.commentsLastModeratedTime, order: .descending)

request.load({ (response) in

    self.comments = response.results // Array of BVComment objects
    // display comments in your UI

}) { (error) in

    print("ERROR fetching comments: \(error.first!.localizedDescription)")

}
BVCommentsRequest *request = [[BVCommentsRequest alloc] initWithReviewId:@"myReviewId" limit:99 offset:0];

// Optionally, comments can have includes, filters, and sorts added to the request.
[request addInclude:BVCommentIncludeTypeReviews];
[request addCommentSort:BVSortOptionCommentsLastModeratedTime order:BVSortOrderDescending];
[request addFilter:BVCommentFilterTypeContentLocale filterOperator:BVFilterOperatorEqualTo value:@"en_US"];

[request load:^(BVCommentsResponse * _Nonnull response) {
    // success
    self.comments = response.results; // Array of BVComment objects
    // display comments in your UI

} failure:^(NSArray * _Nonnull errors) {
    // error
    NSLog(@"ERROR Loading Comments: %@", errors.firstObject.localizedDescription);
}];

Loading review comments

Comments can be loaded either by a single comment ID, or you can load comments by a review ID with limit and offset parameters. Simply construct a BVCommentsRequest object and choose one of the default initializers provided. The examples provided below demonstrate how to fetch a list of comments from a given review ID.

let limit: UInt16 = 99
let offset: UInt16 = 0
let commentQuery: BVCommentsQuery =
    BVCommentsQuery(
        productId: " myProductId ",
        reviewId: " myReviewId",
        limit: limit,
        offset: offset)
    .include(.reviews)
    .filter((BVCommentsQuery.Filter.contentLocale(Locale(identifier: "en_US")), .equalTo))
    .sort(.lastModeratedTime, order: .descending)
    .handler {
        (response: BVConversationsQueryResponse < BVComment > ) in
        if
        case .failure = response {
            // handle failure appropriately 
            return
        }
        guard
        case let.success(_, comments) = response
        else {
            return
        }
        self.comments = comments // Array of BVComment objects 
        // display comments in your UI 
    }

Showing bulk ratings

To show product rating statistics on a category page, use a BVBulkRatingsRequest. For example, on a category page like this one:

Getting each product's rating statistics can be done with the following single request:

// Load rating statistics for four products. Can load up to 50 per request.
let productIds = ["test1", "test2", "test3", "test4"]
let request = BVBulkRatingsRequest(productIds: productIds, statistics: .All)
// Load rating statistics for four products. Can load up to 50 per request.
NSArray* productIds = @[@"test1", @"test2", @"test3", @"test4"];
BVBulkRatingsRequest* request = [[BVBulkRatingsRequest alloc] initWithProductIds:productIds statistics:BulkRatingsStatsTypeReviews];

Which can be loaded with:

request.load({ (response: BVBulkRatingsResponse) in

    let ratings = response.results

    for rating in ratings {
        let productId = rating.productId
        let averageOverallRating = rating.reviewStatistics?.averageOverallRating
        let totalReviewCount = rating.reviewStatistics?.totalReviewCount
    }

}) { (errors: [NSError]) in
    // handle failure appropriately
}
[request load:^(BVBulkRatingsResponse * _Nonnull response) {

    NSArray* ratings = response.results;

    for (BVProductStatistics* rating in ratings) {
        NSString* productId = rating.productId;
        NSNumber* averageOverallRating = rating.reviewStatistics.averageOverallRating;
        NSNumber* totalReviewCount = rating.reviewStatistics.totalReviewCount;
    }

} failure:^(NSArray * _Nonnull errors) {
    // handle failure appropriately
}];

Showing bulk ratings

To show product rating statistics on a category page, use a BVProductStatisticsQuery. For example, on a category page like this one:

Getting each product's rating statistics can be done with the following single request:

let productIds = ["test1", "test2", "test3", "test4"]
let productStatisticsQuery = BVProductStatisticsQuery(productIds: productIds)
    .handler {
        (response: BVConversationsQueryResponse < BVProductStatistics > ) in
        if
        case .failure(let error) = response {
            // handle failure appropriately 
            return
        }
        guard
        case let.success(_, productStatistics) = response
        else {
            return
        }
        let ratings = productStatistics
        for rating in ratings {
            let productId = rating.productId
            let averageOverallRating = rating.reviewStatistics ? .averageOverallRating
            let totalReviewCount = rating.reviewStatistics ? .totalReviewCount
        }
    }
productStatisticsQuery.async(

Loading an author's profile

An author's profile for Conversations begins with a BVAuthorRequest object. This request object is all you need to create parameters and obtain an author's profile. The response for an author is found in the response object BVAuthorResponse. Author profile responses can include Reviews, Questions, and Answers written by the author and approved for publishing.

Badge display

Please note that image links are not returned from the Conversations API. The display for Conversation API clients is left up to the client's creative interpretation. For more information please see the Conversations Developer documentation on Badges.

let request = BVAuthorRequest(authorId: "theAuthorsId")
    // stats includes, optional
    .includeStatistics(.answers)
    .includeStatistics(.questions)
    .includeStatistics(.reviews)
    // other includes, optional
    .include(.reviews, limit: 10)
    .include(.questions, limit: 10)
    .include(.answers, limit: 10)
    .include(.reviewComments, limit: 10)
    // sorts, optional
    .sortIncludedAnswers(.submissionTime, order: .descending)
    .sortIncludedReviews(.submissionTime, order: .descending)
    .sortIncludedQuestions(.submissionTime, order: .descending)

request.load({ (response) in
    // success -- load data into your UI
}) { (error) in
    // error - handle error
}
BVAuthorRequest *request = [[BVAuthorRequest alloc] initWithAuthorId:authorId];
[request includeStatistics:BVAuthorContentTypeReviews];
[request includeStatistics:BVAuthorContentTypeQuestions];
[request includeStatistics:BVAuthorContentTypeAnswers];
[request includeContent:BVAuthorContentTypeReviews limit:5];
[request includeContent:BVAuthorContentTypeQuestions limit:5];
[request includeContent:BVAuthorContentTypeAnswers limit:5];
[request includeContent:BVAuthorContentTypeReviewComments limit:5];

[request load:^(BVAuthorResponse * _Nonnull response) {

    // Success!
    NSLog(@"Succesfully loaded profile: %@", response);

} failure:^(NSArray * _Nonnull errors) {

    // Error : (
    NSLog(@"ERROR loading author: %@", errors.description);

}];

Loading an author's profile

An author's profile for Conversations begins with a BVAuthorQuery object. This request object is all you need to create parameters and obtain an author's profile. The response for an author is found in the response object BVConversationsQueryResponse<BVAuthor>. Author profile responses can include Reviews, Questions, and Answers written by the author and approved for publishing.

Badge display

Please note that image links are not returned from the Conversations API. The display for Conversation API clients is left up to the client's creative interpretation. For more information please see the Conversations Developer documentation on Badges.

let authorQuery =
    BVAuthorQuery(authorId: "theAuthorsId")
    // stats includes, optional 
    .stats(.answers)
    .stats(.questions)
    .stats(.reviews)
    // other includes, optional 
    .include(.reviews, limit: 10)
    .include(.questions, limit: 10)
    .include(.answers, limit: 10)
    .include(.comments, limit: 10)
    // sorts, optional 
    .sort(.answers(.submissionTime), order: .descending)
    .sort(.reviews(.submissionTime), order: .descending)
    .sort(.questions(.submissionTime), order: .descending)
    .configure(configuration)
    .handler {
        (response: BVConversationsQueryResponse < BVAuthor > ) in
        if
        case .failure(let error) = response {
            // error - handle error 
            return
        }
        guard
        case let.success(_, authors) = response
        else {
            // success -- load data into your UI 
            return
        }
    }
authorQuery.async(urlSession: urlSession)

Showing bulk ratings

To show product rating statistics on a category page, use a BVBulkRatingsRequest. For example, on a category page like this one:

Getting each product's rating statistics can be done with the following single request:

// Load rating statistics for four products. Can load up to 50 per request.
let productIds = ["test1", "test2", "test3", "test4"]
let request = BVBulkRatingsRequest(productIds: productIds, statistics: .All)
// Load rating statistics for four products. Can load up to 50 per request.
NSArray* productIds = @[@"test1", @"test2", @"test3", @"test4"];
BVBulkRatingsRequest* request = [[BVBulkRatingsRequest alloc] initWithProductIds:productIds statistics:BulkRatingsStatsTypeReviews];

Which can be loaded with:

request.load({ (response: BVBulkRatingsResponse) in

    let ratings = response.results

    for rating in ratings {
        let productId = rating.productId
        let averageOverallRating = rating.reviewStatistics?.averageOverallRating
        let totalReviewCount = rating.reviewStatistics?.totalReviewCount
    }

}) { (errors: [NSError]) in
    // handle failure appropriately
}
[request load:^(BVBulkRatingsResponse * _Nonnull response) {

    NSArray* ratings = response.results;

    for (BVProductStatistics* rating in ratings) {
        NSString* productId = rating.productId;
        NSNumber* averageOverallRating = rating.reviewStatistics.averageOverallRating;
        NSNumber* totalReviewCount = rating.reviewStatistics.totalReviewCount;
    }

} failure:^(NSArray * _Nonnull errors) {
    // handle failure appropriately
}];

Showing bulk ratings

To show product rating statistics on a category page, use a BVProductStatisticsQuery. For example, on a category page like this one:

Getting each product's rating statistics can be done with the following single request:

let productIds = ["test1", "test2", "test3", "test4"]
let productStatisticsQuery = BVProductStatisticsQuery(productIds: productIds)
    .handler {
        (response: BVConversationsQueryResponse < BVProductStatistics > ) in
        if
        case .failure(let error) = response {
            // handle failure appropriately 
            return
        }
        guard
        case let.success(_, productStatistics) = response
        else {
            return
        }
        let ratings = productStatistics
        for rating in ratings {
            let productId = rating.productId
            let averageOverallRating = rating.reviewStatistics ? .averageOverallRating
            let totalReviewCount = rating.reviewStatistics ? .totalReviewCount
        }
    }
productStatisticsQuery.async(

Loading Review Highlights

Load Review Highlights (PROS and CONS) by specifying a product ID and client ID.

  1. Construct a BVReviewHighlightsRequest object with the initializer provided and pass the product ID. The example provided below demonstrates how to fetch Review Highlights for a given product ID.
    let request = BVReviewHighlightsRequest(productId: "productId")
    request.load({ (response) in
    
    if let positives = response.reviewHighlights.positives { // Array of BVReviewHighlight objects
      // display positives in your UI
    
      for positive in positives {
        let title = positive.title // PRO title
      }
    }
    
    if let negatives = response.reviewHighlights.negatives { // Array of BVReviewHighlight objects
      // display negatives in your UI
    
      for negative in negatives {
        let title = negative.title // CON title
      }
    }
    
    }) { (error) in
      // handle failure appropriately
    }
    
    BVReviewHighlightsRequest *reviewHighlightsRequest = [[BVReviewHighlightsRequest alloc] initWithProductId:@"productId"];
    [reviewHighlightsRequest load:^(BVReviewHighlightsResponse * _Nonnull response) {
      NSArray<BVReviewHighlight *> *positives = response.reviewHighlights.positives;
    
      for (BVReviewHighlight *positive in positives) {
        NSString *title = positive.title; // PRO title
      }
    
      NSArray<BVReviewHighlight *> *negatives = response.reviewHighlights.negatives;
    
      for (BVReviewHighlight *negative in negatives) {
        NSString *title = negative.title; // CON title
      }
    
    } failure:^(NSArray<NSError *> * _Nonnull errors) {
      // error
      NSLog(@"ERROR Loading Review Highlights: %@", errors.firstObject.localizedDescription);
    }];
    
  2. Pass the client ID to the configuration before creating the request to fetch Review Highlights, as shown in the following code block:
    let configDict = ["clientId": "YOUR_CLIENT_ID",
    "apiKeyConversations": "YOUR_API_KEY"];
    BVSDKManager.configure(withConfiguration: configDict, configType: .staging)
    
    NSDictionary *configDict = @{@"clientId" : @"YOUR_CLIENT_ID", @"apiKeyConversations":@"YOUR_API_KEY"};
    [BVSDKManager configureWithConfiguration:configDict
    configType:BVConfigurationTypeStaging];
    

Loading Review Highlights

Load Review Highlights (PROS and CONS) by passing a client ID and product ID. Simply construct a BVProductReviewHighlightsQuery object with the initializer provided and pass the client ID and product ID. The example provided below demonstrates how to fetch Review Highlights for a given client ID and product ID.

let reviewHighlightsQuery = BVProductReviewHighlightsQuery(clientId: "clientId", productId: "productId")
  .configure(configuration)
  .handler { (response: BVReviewHighlightsQueryResponse<BVReviewHighlights>) in
    if case .failure(let error) = response {
      // handle failure appropriately
      return
    }

    guard case let .success(reviewHighlights) = response else { 
      return 
    }

    if let positives = reviewHighlights.positives { // Array of BVReviewHighlight objects
      // display positives in your UI

      for positive in positives {
        let title = positive.title // PRO title
      }
    }

    if let negatives = reviewHighlights.negatives { // Array of BVReviewHighlight objects
      // display negatives in your UI
      for negative in negatives {
        let title = negative.title // CON title
      } 
    }
  }

  reviewHighlightsQuery.async(urlSession: urlSession)