Content Display

This documentation explains how user-generated content (UGC), 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

📘

If you need to check the list of possible parameters for any of the below APIs, please refer the below links and select the API from section contents:

The available content types are described below in more detail.

Loading a product display page

Objective-C SDK

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.
BVProductDisplayPageRequest* request = [[BVProductDisplayPageRequest alloc]
initWithProductId:@"test1"];
[request includeStatistics:BVProductIncludeTypeValueReviews];
[request includeStatistics:BVProductIncludeTypeValueQuestions];
// request product information, including statistics on reviews and questions/answers.
 let request = BVProductDisplayPageRequest(productId: "test1")
  .includeStatistics(.reviews)
  .includeStatistics(.questions)

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 statistics on reviews and questions/answers.
BVProductDisplayPageRequest* request1 = [[BVProductDisplayPageRequest alloc]
initWithProductId:@"test1"];
[request includeProductIncludeTypeValue:BVProductIncludeTypeValueReviews limit:10];
[request includeProductIncludeTypeValue:BVProductIncludeTypeValueQuestions limit:5];
[request sortByReviewsSortOptionValue:(BVReviewsSortOptionValueReviewSubmissionTime) monotonicSortOrderValue:(BVMonotonicSortOrderValueDescending)];
// request product information, including the first 5 questions and 10 reviews, sorted by their submissionTime.
let request = BVProductDisplayPageRequest(productId: "test1")
  .include(.reviews, limit: 10)
  .include(.questions, limit: 5)
  .sort(by: .reviewSubmissionTime, monotonicSortOrderValue: .descending)

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:^(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
}];
// 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:[Error]) in
    // 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;
 
@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
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: [Error]) in
            // handle error appropriately
        }
 
    }
}

Swift SDK

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(config)  
productQuery.async()

Product Search Query

let productSearchQuery = BVProductSearchQuery(searchQuery: "Large dryer")  
productSearchQuery.configure(config)  
  .handler { (response: BVConversationsQueryResponse<BVProduct>) in  
    if case .failure(let error) = response {  
      // handle failure appropriately  
      return  
    }
  guard case let .success(\_, products) = response else {
  return
}
//success
}

productSearchQuery.async()

The result returns products that have both large and dryer in the external ID, product name, product brand, product description, category name or category hierarchy names.


Loading more reviews

Objective-C SDK

As shown previously, you should use a ProductDisplayPageRequest to load the first page of UGC 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.
@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");
}];
// 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)
}

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.
BVReviewsRequest* request = [[BVReviewsRequest alloc] initWithProductId:@"test1" limit:10 offset:20];
[request filterOnReviewFilterValue:BVReviewFilterValueHasPhotos relationalFilterOperatorValue:BVRelationalFilterOperatorValueEqualTo value:@"true"];
[request sortByReviewsSortOptionValue:BVReviewsSortOptionValueReviewSubmissionTime monotonicSortOrderValue:BVMonotonicSortOrderValueDescending];
// request 10 reviews that have photos, starting at index 0, sorted by overall rating.
let request = BVReviewsRequest(productId: "test1", limit: 10, offset: 0)
  .filter(on: .hasPhotos, relationalFilterOperatorValue: .equalTo, value: "true")
  .sort(by: .reviewRating, monotonicSortOrderValue: .ascending)

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 BVSDK;
 
@interface DemoReviewsViewController: UIViewController
 
@property (nonatomic, weak) IBOutlet BVReviewsTableView *tableView;
 
@end
 
// ...
 
@implementation DemoReviewsViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
}
 
@end
import UIKit
import BVSDK
 
class DemoReviewsViewController: UIViewController {
 
    @IBOutlet weak var tableView : BVReviewsTableView!
 
    override func viewDidLoad() {
        super.viewDidLoad()
    }
 
}
  • 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 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
    
    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
            }
        }
    }
    
  • 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 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
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.register(UINib(nibName: "DemoReviewTableViewCell", bundle: nil), forCellReuseIdentifier: "DemoReviewTableViewCell")
 
        let request = BVReviewsRequest(productId: "test1", limit: 10, offset: 20)
 
        self.tableView.load(request, success: { (response: BVReviewsResponse) in
            self.reviews = response.results
            self.tableView.reloadData()
        }) { (errors: [Error]) in
            // handle failure appropriately
 
        }
     }
 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.reviews.count
    }
 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "DemoReviewTableViewCell") as! DemoReviewTableViewCell
        cell.review = self.reviews[indexPath.row]
        return cell
    }
}

Swift SDK

let reviewQuery = BVReviewQuery(productId: "test1", limit: 10, offset: 0)
 .configure(config)
.handler {
(response: BVConversationsQueryResponse < BVReview > ) in
                if case .failure(let error) = response {
                    // error
                    return
                }
                guard case let.success(_, reviews) = response
                else {
                    return
                }
                // success
}
 
 reviewQuery.async()

Filter Reviews

let reviewQuery = BVReviewQuery(productId: "test1", limit: 10, offset: 4)  
    .filter((.hasPhotos(true), .equalTo))  
    .filter((.hasComments(false), .equalTo))  
    .configure(config)  
    .handler {}

You can also use exhaustive set of filter options whilst constructing BVReviewQuery mentioned on this link.

Sort Reviews

let reviewQuery = BVReviewQuery(productId: "test1", limit: 10, offset: 4)  
    .sort(.rating, order: .ascending)  
    .configure(config)  
    .handler {}

You can also use exhaustive set of sort options whilst constructing BVReviewQuery mentioned on this link.


Loading Questions & Answers

Objective-C SDK

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.
@property (weak, nonatomic) IBOutlet BVQuestionsTableView *questionsTableView;
@property NSArray *questions;
 
// Now load the questions from the BVQuestionsTableView.
    // request 10 questions, starting at index 20
    BVQuestionsAndAnswersRequest* request = [[BVQuestionsAndAnswersRequest alloc] initWithProductId:@"test1" limit:10 offset:20];
    [self.questionsTableView load:request success:^(BVQuestionsAndAnswersResponse * _Nonnull response) {
        self.questions = response.results;
        [self.questionsTableView reloadData];
    } failure:^(NSArray<nserror *=""> * _Nonnull errors) {
         NSLog(@"Error loading questions");
    }];
</nserror>
// 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 = BVQuestionsAndAnswersRequest(productId: "test1", limit: 10, offset: 20)
 
questionsTableView.load(questionsRequest, success: { (response) in
 
            self.questions = response.results
            self.questionsTableView.reloadData()
 
            }) { (error) in
 
            print(error)
 
        }

A QuestionsAndAnswersRequest requires the three parameters:

  • 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 questions 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.
BVQuestionsAndAnswersRequest* request = [[BVQuestionsAndAnswersRequest alloc] initWithProductId:@"test1" limit:10 offset:0];
[request filterOnQuestionFilterValue:BVQuestionFilterValueQuestionHasAnswers relationalFilterOperatorValue:BVRelationalFilterOperatorValueEqualTo value:@"true"];
[request sortByQuestionsSortOptionValue:BVQuestionsSortOptionValueQuestionLastModeratedTime monotonicSortOrderValue:BVMonotonicSortOrderValueDescending];

// 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)
  .filter(on: .questionHasAnswers, relationalFilterOperatorValue: .equalTo, value: "true")
  .sort(by: .questionSubmissionTime, monotonicSortOrderValue: .ascending)

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 BVSDK;
 
@interface DemoQuestionsViewController: UIViewController
 
@property (nonatomic, weak) IBOutlet BVQuestionsTableView *tableView;
 
@end
 
// ...
 
@implementation DemoQuestionsViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
}
 
@end
import UIKit
import BVSDK
 
class DemoQuestionViewController: UIViewController {
 
    @IBOutlet weak var questionsTableView : BVQuestionsTableView!
 
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
  • 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 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

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
        }
    }
}
  • 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 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:request success:^(BVQuestionsAndAnswersResponse * _Nonnull response) {
         self.questions = response.results;
         [self.tableView reloadData];
    } failure:^(NSArray<NSError *> * _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
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.register(UINib(nibName: "DemoQuestionTableViewCell", bundle: nil), forCellReuseIdentifier: "DemoQuestionTableViewCell")
 
        let request = BVQuestionsAndAnswersRequest(productId: "test1", limit: 10, offset: 20)
        self.tableView.load(request, success: { (response: BVQuestionsAndAnswersResponse) in
            self.questions = response.results
            self.tableView.reloadData()
        }) { (errors: [Error]) in
            // handle failure appropriately
 
        }
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.questions.count
    }
 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "DemoQuestionTableViewCell") as! DemoQuestionTableViewCell
      cell.question = self.questions[indexPath.row]
 
      return cell
    }
}

Swift SDK

let questionQuery = BVQuestionQuery(productId: "test1", limit: 10, offset: 0)
  .configure(config)
  .handler {
    (response: BVConversationsQueryResponse < BVQuestion > ) in
    if case .failure(let error) = response {
        // error
        return
    }
    guard case let.success(\_, questions) = response
    else {
        return
    }
    // success
  }
questionQuery.async()

        

Filter Questions & Include Answers

let questionQuery = BVQuestionQuery(productId: "test1", limit: 10,offset: 0)
    .include(.answers)
    .filter((.hasAnswers(true), .equalTo))
    .configure(config)
    .handler {}
    

You can also use exhaustive set of filter options whilst constructing BVQuestionQuery mentioned on this link.

Sort Questions

let questionQuery = BVQuestionQuery(productId: "test1", limit: 10, offset: 0)  
        .sort(.totalAnswerCount, order: .descending)  
        .configure(config)  
        .handler {}
    

You can also use exhaustive set of sort options whilst constructing BVQuestionQuery mentioned on this link.


Loading review comments

Objective-C SDK

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.

BVCommentsRequest *request = [[BVCommentsRequest alloc] initWithProductId:@"myProductId" andReviewId:@"myReviewId" limit:99 offset:0];
 
// Optionally, comments can have includes, filters, and sorts added to the request.
[request includeCommentIncludeTypeValue:BVCommentIncludeTypeValueCommentReviews];
[request sortByCommentsSortOptionValue:BVCommentsSortOptionValueCommentLastModeratedTime monotonicSortOrderValue:BVMonotonicSortOrderValueDescending];
[request filterOnCommentFilterValue:BVCommentFilterValueCommentContentLocale relationalFilterOperatorValue:BVRelationalFilterOperatorValueEqualTo value:@"en_US"];
 
[request load:^(BVCommentsResponse * _Nonnull response) {
  // success
  self.comments = response.results; // Array of BVComment objects
 
  // display comments in your UI
 
} failure:^(NSArray<NSError *> * _Nonnull errors) {
  // error
  NSLog(@"ERROR Loading Comments: %@", errors.firstObject.localizedDescription);
}];
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)")
 
}

Swift SDK

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 BVCommentsQuery 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 commentQuery = BVCommentsQuery(productId: "productId", reviewId: "reviewId",limit: 10)  
        commentQuery  
            .configure(config)  
            .handler {  
                (response: BVConversationsQueryResponse \< BVComment > ) in  
                if case .failure(let error) = response {  
                    // error  
                    return  
                }  
                guard case let.success(\_, comments) = response  
                else {  
                    return  
                }  
                // success  
            }
commentQuery.async()

Filter Review Comments

let commentQuery = BVCommentsQuery(productId: "productId", reviewId: "reviewId",limit: 10)
    commentQuery
        .filter((.contentLocale(Locale(identifier: "en\_US")), .equalTo))
        .configure(config)
        .handler {}

You can also use exhaustive set of filter options whilst constructing BVCommentsQuery mentioned on this link.

Sort Review Comments

let commentQuery = BVCommentsQuery(productId: "productId", reviewId: "reviewId",limit: 10)  
       commentQuery  
         .sort(.submissionTime, order: .descending)  
         .configure(config)  
         .handler {}

You can also use exhaustive set of sort options whilst constructing BVCommentsQuery mentioned on this link.


Showing bulk ratings

Objective-C SDK

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.
NSArray* productIds = @[@"test1", @"test2", @"test3", @"test4"];
BVBulkRatingsRequest* request = [[BVBulkRatingsRequest alloc] initWithProductIds:productIds statistics: BVBulkRatingIncludeTypeValueBulkRatingReviews];
// 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: .bulkRatingAll)

Which can be loaded with:

[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
}];
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: [Error]) in
    // handle failure appropriately
}

Swift SDK

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 usLocale: Locale = Locale(identifier: "en_US")
 
guard let productStatisticsQuery =
    BVProductStatisticsQuery(productIds: productIds) else {
            return
    }
 
productStatisticsQuery
    .stats(.nativeReviews)
    .stats(.reviews)
    .filter((.contentLocale(usLocale), .equalTo))
    .configure(config)
    .handler {
            (response: BVConversationsQueryResponse<BVProductStatistics>) in
 
            if case .failure(let error) = response {
              print(error)
              return
            }
 
              guard case let .success(_, productStatistics) = response else {
              return
            }
 
            guard let firstProductStatistic: BVProductStatistics = productStatistics.first,
                let reviewStatistics = firstProductStatistic.reviewStatistics,
                let nativeReviewStatistics = firstProductStatistic.nativeReviewStatistics else {
                     return
                }
            print(reviewStatistics)
            }
 
productStatisticsQuery.async()

You can also use exhaustive set of filter options whilst constructing BVProductStatisticsQuery mentioned on this link.


Loading an author's profile

Objective-C SDK

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.

BVAuthorRequest *request = [[BVAuthorRequest alloc] initWithAuthorId: @"authorId"];
[request includeStatistics:BVAuthorIncludeTypeValueAuthorReviewComments];
[request includeStatistics:BVAuthorIncludeTypeValueAuthorQuestions];
[request includeStatistics:BVAuthorIncludeTypeValueAuthorAnswers];
[request includeAuthorIncludeTypeValue:BVAuthorIncludeTypeValueAuthorAnswers limit:5];
[request includeAuthorIncludeTypeValue:BVAuthorIncludeTypeValueAuthorQuestions limit:5];
[request includeAuthorIncludeTypeValue:BVAuthorIncludeTypeValueAuthorReviewComments limit:5];
[request includeAuthorIncludeTypeValue:BVAuthorIncludeTypeValueAuthorReviews limit:5];
 
[request load:^(BVAuthorResponse * _Nonnull response) {
 
  // Success!
  NSLog(@"Succesfully loaded profile: %@", response);
} failure:^(NSArray * _Nonnull errors) {
 
  // Error : (
    NSLog(@"ERROR loading author: %@", errors.description);
}];
let request = BVAuthorRequest(authorId: "theAuthorsId")
  // stats includes, optional
  .includeStatistics(.authorAnswers)
  .includeStatistics(.authorQuestions)
  .includeStatistics(.authorReviews)
 
  // other includes, optional
  .include(.authorReviews, limit: 10)
  .include(.authorQuestions, limit: 10)
  .include(.authorAnswers, limit: 10)
  .include(.authorReviewComments, limit: 10)
 
  // sorts, optional
  .sort(by: .answerSubmissionTime, monotonicSortOrderValue: .descending)
  .sort(by: .reviewSubmissionTime, monotonicSortOrderValue: .descending)
  .sort(by: .questionSubmissionTime, monotonicSortOrderValue: .descending)
 
  request.load({ (response) in
    // success -- load data into your UI
    print(response)
  }) { (error) in
    // error - handle error
    print(error)
  }

Swift SDK

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: "AuthorId")
  // stats includes
  .stats(.answers)
  .stats(.questions)
  .stats(.reviews)
 
  // other includes
  .include(.reviews, limit: 10)
  .include(.questions, limit: 10)
  .include(.answers, limit: 10)
  .include(.comments, limit: 10)
 
  // sorts
  .sort(.answers(.submissionTime), order: .descending)
  .sort(.reviews(.submissionTime), order: .descending)
  .sort(.questions(.submissionTime), order: .descending)
 
  .configure(config)
  .handler { (response: BVConversationsQueryResponse<BVAuthor>) in
    // success
 
    if case .failure(let error) = response {
      print(error)
      return
    }
 
    guard case let .success(_, authors) = response else {
      return
    }
 
    guard let author: BVAuthor = authors.first,
      let qaStatistics: BVQAStatistics = author.qaStatistics,
      let reviewStatistics: BVReviewStatistics = author.reviewStatistics,
      let ratingDistribution: BVRatingDistribution =
        reviewStatistics.ratingDistribution,
      let averageOverallRating: Double =
        reviewStatistics.averageOverallRating,
      let reviews: [BVReview] = author.reviews,
      let questions: [BVQuestion] = author.questions,
      let answers: [BVAnswer] = author.answers,
      let comments: [BVComment] = author.comments
    else {
      return
    }
 
  }
 
authorQuery.async()

You can also use exhaustive set of filter options whilst constructing BVAuthorQuery mentioned on this link.

You can also use exhaustive set of sort options whilst constructing BVAuthorQuery mentioned on this link.


Loading Review Highlights

Objective-C SDK

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.
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);
}];
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
}
  1. Pass the client ID to the configuration before creating the request to fetch Review Highlights, as shown in the following code block:
NSDictionary *configDict = @{@"clientId" : @"YOUR_CLIENT_ID", @"apiKeyConversations":@"YOUR_API_KEY"};
[BVSDKManager configureWithConfiguration:configDict
configType:BVConfigurationTypeStaging];
let configDict = ["clientId": "YOUR_CLIENT_ID",
"apiKeyConversations": "YOUR_API_KEY"];
BVSDKManager.configure(withConfiguration: configDict, configType: .staging)

Swift SDK

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.

var config: BVReviewHighlightsConfiguration = { () -> BVReviewHighlightsConfiguration in
 
 
let analyticsConfig: BVAnalyticsConfiguration =
        .configuration(locale: Locale(identifier: "en_US"), configType: .staging(clientId: "clientId"))
 
 
        return BVReviewHighlightsConfiguration.display(configType: .staging(clientId: "clientId"), analyticsConfig: analyticsConfig)
       }()
let reviewHighlightsQuery = BVProductReviewHighlightsQuery(clientId: "clientId", productId: “testproductId")
            .configure(config)
            .handler { (response: BVReviewHighlightsQueryResponse<BVReviewHighlights>) in
 
            if case .failure(let error) = response {
                    print(error)
                    return
            }
            guard case let .success(reviewHighlights) = response else {
                    return
            }
            if let negatives = reviewHighlights.negatives {
                for negative in negatives {
                    print(negative.title)
                }
            }
 
            if let positives = reviewHighlights.positives {
                for positive in positives {
                    print(positive.bestExamples?.first?.reviewTitle)
                }
            }
         }
reviewHighlightsQuery.async()