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 documenation explains the mechanics of submitting consumer-generated content (CGC) to Bazaarvoice using the Mobile SDK.

Introduction

The BVSDK makes it easy to upload consumer-generated content (Reviews, Questions, Answers) to the Bazaarvoice platform. The full API documentation details what each field represents which is not covered here. Contact Bazaarvoice to set up Conversations if you haven't done so already.

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.

Using Conversations Submission API

After you install the Mobile SDK, complete the following steps to submit consumer-generated content.

Step 1: View form options

For each option available in a submission form, there is a boolean flag determining whether it is a required field or not. You can discover this by iterating through the available form fields, which can be found by making a preview submission request.

These form fields may also contain extra information, such as available submission values, and keys for fields specific to your config such as context data values, etc.

review.load({ (response: BVReviewSubmissionResponse) in
    for (formFieldIdentifier, formField) in response.formFields {
      // formFieldIdentifier is the name of the key that must be used for submission
      // formField contains metadata
      let isRequired = formField.required; // Whether this field is required or optional
    }
  }, failure: { (errors: [NSError]) in
    // handle error
  }
})
reviewSubmission 
 .handler { result in 
  if case let .failure(errors) = result { 
   errors.forEach { print($0) } 
   return 
  }      guard case let .success(meta, _) = result else { 
   return 
  }      if let formFields = meta.formFields { 
    for formField in formFields { 
      // formFieldIdentifier is the name of the key that must be used for submission 
      // formField contains metadata 
      let formFieldIdentifier = formField.identifier 
      let isRequired = formField.required // Whether this field is required or optional 
    } 
  } 
}    reviewSubmission.async()
      

Step 2: Send submission request

Review submission

Create a BVReviewSubmission object and fill out appropriate fields.

A BVReviewSubmission object requires a reviewTitle, reviewText, rating, and productId (for which this review corresponds to).
let review = BVReviewSubmission(reviewTitle: "Review title goes here",
                               reviewText: "Review text goes here",
                                   rating: 4,
                                productId: "test1")
review.userNickname = userNickname // "Samantha55"
review.userId = userId             // user's external ID
review.userEmail = userEmail       // "test@test.com"
review.sendEmailAlertWhenPublished = true
review.agreedToTermsAndConditions  = true

// user added a photo to this review
review.addPhoto(userPhoto, withPhotoCaption: userPhotoCaption)

// add youtube video link, if your configuration supports it
review.addVideoURL(userYouTubeUrl, withCaption: userVideoCaption)

// Submitting this review is as easy as calling submit 
review.submit({ (reviewSubmission: BVSubmissionResponse<BVSubmittedReview>) in 
  // review submitted successfully! 
}, failure: { (errors: [Error]) in 
  // handle failure appropriately 
}) 
BVReviewSubmission* review = [[BVReviewSubmission alloc] initWithReviewTitle:@"Review title goes here"
                                                                reviewText:@"Review text goes here"
                                                                    rating:4
                                                                 productId:@"test1"];
review.userNickname = userNickname; // "Samantha55"
review.userId = userId;             // user's external ID
review.userEmail = userEmail;       // "test@test.com"
review.sendEmailAlertWhenPublished = [NSNumber numberWithBool:YES];
review.agreedToTermsAndConditions  = [NSNumber numberWithBool:YES];

// user added a photo to this review
[review addPhoto: userPhoto withPhotoCaption: userPhotoCaption];

// add youtube video link, if your configuration supports it
[review addVideoURL: userYouTubeUrl withCaption: userVideoCaption];

// Submitting this review is as easy as calling submit 
[review submit:^(BVSubmissionResponse<BVSubmittedReview *> * _Nonnull) { 
  // review submitted successfully! 
} failure:^(NSArray<NSError *> * _Nonnull errors) { 
  // handle failure appropriately 
}]; 
 let review: BVReview = BVReview(productId: "test1", 
      reviewText: "Review text goes here", 
      reviewTitle: "Review title goes here", 
      reviewRating: 4) 
  guard let reviewSubmission = BVReviewSubmission(review) else { 
      return nil 
  } 
  let photo: BVPhoto = BVPhoto(png, userPhotoCaption) 
  (reviewSubmission 
    <+> .sendEmailWhenPublished(true) 
    <+> .nickname(userNickname)    // "Samantha55" 
    <+> .email(userEmail)        // "test@test.com" 
    <+> .identifier(userId)        // user's external ID 
    <+> .agree(true) 
    <+> .photos([BVPhoto(userPhoto, userPhotoCaption)])    // user added a photo to this review 
    <+> .videos([BVVideo(userYouTubeUrl, caption: userVideoCaption)]))    // add youtube video link, if your configuration supports it 
    .configure(configuration) 
    .handler { result in 
      if case let .failure(errors) = result { 
        // handle failure appropriately 
        return 
      } 
      guard case let .success(meta, _) = result else { 
        return 
      } 
      // review submitted successfully! 
  } 
    // Submitting this review is as easy as calling async 
    reviewSubmission.async() 
      

Question submission

Submitting a question is nearly identical to submitting a review, detailed above. Create an instance of BVQuestionSubmission, fill in some parameters, and submit it!

A QuestionSubmission object requires a productId for which this question corresponds to.
// create question submission and fill out with user-input values
let question = BVQuestionSubmission(productId: "test1")
question.questionSummary = userQuestion // "Heavy?"
question.questionDetails = userQuestion // "How much does this weigh?"
question.userNickname = userNickname // "Samantha55"
question.userId = userId             // user's external ID
question.userEmail = userEmail       // "test@test.com"
question.agreedToTermsAndConditions  = true

// submit the question 
question.submit({ (questionSubmission: BVSubmissionResponse<BVSubmittedQuestion>) in 
  // question submitted successfully! 
}, failure: { (errors: [Error]) in 
 // handle failure appropriately 
}) 
// create question submission and fill out with user-input values
BVQuestionSubmission* question = [[BVQuestionSubmission alloc] initWithProductId:@"test1"];
question.questionSummary = userQuestion; // "Heavy?"
question.questionDetails = userQuestion; // "How much does this weigh?"
question.userNickname = userNickname;    // "Samantha55"
question.userId = userId;                // user's external ID
question.userEmail = userEmail;          // "test@test.com"
question.agreedToTermsAndConditions;  [NSNumber numberWithBool:YES];

// submit the question 
[question submit:^(BVSubmissionResponse<BVSubmittedQuestion *> * _Nonnull response) { 
  // question submitted successfully! 
} failure:^(NSArray<NSError *> * _Nonnull errors) { 
  // handle failure appropriately 
}]; 
      let question: BVQuestion = 
      BVQuestion( 
        productId: "test1", 
        questionDetails: userQuestion, // "How much does this weigh?" 
        questionSummary: userQuestion, // "Heavy?" 
        isUserAnonymous: false) 
    guard let questionSubmission = BVQuestionSubmission(question) else { 
        return nil 
    } 
    (questionSubmission 
      <+> .nickname(userNickName) // "Samantha55" 
      <+> .email(userEmail) // "test@test.com" 
      <+> .identifier(userId) // user's external ID 
      <+> .agree(true) 
      .configure(configuration) 
      .handler { result in 
        if case let .failure(errors) = result { 
    // handle failure appropriately 
        return 
        } 
        guard case let .success(meta, _) = result else { 
          return 
        } 
    // question submitted successfully!         
    } 
    questionSubmission.async() 
      

Progressive Submission

This documentation explains how consumer-generated content (CGC) can be submitted and updated using the Progressive Submission API.

Progressive submission should be used in scenarios where clients want to display multiple review request forms for a number of items. Additionally, progressive submission supports partial or incremental submissions across different devices.

Initiating Progressive Submit

Sending a InitiateSubmitRequest returns the current state of the reviews associated with the products and userId passed in the request. It also returns a unique submissionSessionToken that s used to submit content and update reviews.

The initiateSubmitRequest object requires a userId or an encrypted User Agent String (UAS), at least one productId, and a locale.
let initiateSubmitRequest = BVInitiateSubmitRequest(productIds: ["product1", "product2", "product3"]) 
initiateSubmitRequest.userId = user 
initiateSubmitRequest.locale = locale 

initiateSubmitRequest.submit({ (initiateSubmitResponseData) in 
  /// Submission was successfully initiated 
}, failure: { (errors) in 
  ///Submission initiation failed with errors 
}) 
Progressive Submission

Once the initiateSubmitResponse has returned and the SubmissionSessionToken has been received, You can then start to construct a progressiveSubmissionRequest. The request returns a review object that holds the submitted review fields, and the sessions token that was used in the request.

The submission object requires a userId and userEmail, or UserToken (User Agent String), productId, locale, submissionSessionToken, SubmissionFields
let submission = BVProgressiveSubmitRequest(productId:"productId") 
submission.submissionSessionToken = submissionSessionToken 
submission.locale = locale 
submission.userToken = userToken 
submission.submissionFields = fields 

submission.submit({ (submittedReview) in 
  /// Submission was sucessful 
}, failure: { (errors) in 
  ///submission failed with errors 
}) 
Photo Submission

To submit a photo with a ProgressiveSubmission you will need to attach a photo’s url to the progressiveSubmission’s SubmissionFields after uploading the photo using the ‘PhotoSubmissionRequest'.

let photo = BVPhotoSubmission( 
  photo: image, 
  photoCaption: photoCaption, 
  photoContentType: .review) 

  photo.submit({ (photoSubmissionResponse) in 
    //Assign returned URL to photourl field 
    fields["photourl_1"] = photoURL; 
    request.submissionFields = fields 

  }) { (errors) in 
    //photo upload failed with errors 
} 
Initiating Progressive Submit

Sending a InitiateSubmitRequest returns the current state of the reviews associated with the products and userId passed in the request. It also returns a unique submissionSessionToken that s used to submit content and update reviews.

BVInitiateSubmitRequest object requires a userId or an encrypted User Agent String (UAS), at least one productId, and a locale.
BVInitiateSubmitRequest * initiateSubmitRequest = [[BVInitiateSubmitRequest alloc] initWithProductIds:@[@"product1", @"product2", @"product3"]]; 
initiateSubmitRequest.userId = @"test109"; 
initiateSubmitRequest.locale = @"en_US"; 

[initiateSubmitRequest submit:^(BVSubmissionResponse<BVInitiateSubmitResponseData *> * _Nonnull response) { 
  // Submission was successfully initiated 
} failure:^(NSArray<NSError *> * _Nonnull errors) { 
  //Submission initiation failed with errors 
}]; 
    
Progressive Submission

Once the initiateSubmitResponse has returned and the SubmissionSessionToken has been received, You can then start to construct a progressiveSubmissionRequest object. The request returns a review object that holds the submitted review fields, and the sessions token that was used in the request.

BVProgressiveSubmitRequest object requires a userId and userEmail, or UserToken (User Agent String), productId, locale, submissionSessionToken, SubmissionFields
BVProgressiveSubmitRequest *request = [[BVProgressiveSubmitRequest alloc] 
initWithProductId:@"sampleProduct"]; 

request.submissionSessionToken = sessionToken; //”unique session token” 
request.locale = locale;  //”user locale” 
request.userToken = userToken; //”encrypted user token” 
request.submissionFields = fields; //submission field dictionary 

[request submit:^(BVSubmissionResponse<BVProgressiveSubmitResponseData *> * _Nonnull response) { 
  /// Submission was sucessful 
} failure:^(NSArray<NSError *> * _Nonnull errors) { 
  ///submission failed with errors 
}]; 
Photo Submission

To submit a photo with a ProgressiveSubmission you will need to attach a photo’s url to the progressiveSubmission’s SubmissionFields after uploading the photo using the ‘PhotoSubmissionRequest'.

 BVPhotoSubmission *photo = [[BVPhotoSubmission alloc] initWithPhoto:image 
  photoCaption:photoCaption 
  photoContentType:contentType]; 

[photo upload:^(NSString * _Nonnull photoURL, 
  NSString * _Nonnull photoCaption) { 
    //Assign returned URL to photourl field 
    fields[@"photourl_1"] = photoURL; 
    request.submissionFields = fields 
  } failure:^(NSArray<NSError *> * _Nonnull errors) { 
    //photo upload failed with errors 
}]; 
Initiating Progressive Submit

Sending a InitiateSubmitRequest returns the current state of the reviews associated with the products and userId passed in the request. It also returns a unique submissionSessionToken that s used to submit content and update reviews.

BVMultiProductQuery object requires a userId or an encrypted User Agent String (UAS), at least one productId, and a locale.
let multiProduct: BVMultiProduct = BVMultiProduct(productIds: ["product4", "product2", "product3"], locale: "", userId: "userId")

guard let multiProductSubmission = BVMultiProductQuery(multiProduct) else {
  return
}

BVMultiProductQuery(
  multiProductSubmission.configure(config)
  
  multiProductSubmission
  .handler { result in

    if case let .failure(errors) = result, let error = errors.first {
      return
    }
    guard case .success(_, _) = result else {
      return
    }
}

multiProductSubmission.async()
    
Progressive Submission

Once the initiateSubmitResponse has returned and the SubmissionSessionToken has been received, You can then start to construct a BVProgressiveReviewSubmission object. The request returns a review object that holds the submitted review fields, and the sessions token that was used in the request.

BVProgressiveReviewSubmission object requires a userId and userEmail, or UserToken (User Agent String), productId, locale, submissionSessionToken, SubmissionFields
var submissionFields = BVProgressiveReviewFields()

submissionFields.rating = 4
submissionFields.title = "my favorite product ever!"
submissionFields.reviewtext = "favorite product"
submissionFields.agreedToTerms = true
submissionFields.sendEmailAlert = true
submissionFields.isRecommended = true

var reviewSubmission = BVProgressiveReview(productId:"product10", submissionFields: submissionFields)
reviewSubmission.submissionSessionToken = "Session_Token"
reviewSubmission.locale = "locale"
reviewSubmission.userToken = "User_Token"

guard let progressiveReviewSubmission = BVProgressiveReviewSubmission(reviewSubmission) else {
  return
}

progressiveReviewSubmission.configure(config)

progressiveReviewSubmission
  .handler { result in
    if case let .failure(errors) = result, let error = errors.first {
      return
    }
    
    if case let .success(_ , response) = result {
      print(response)
    }
  }

progressiveReviewSubmission.async()
Photo Submission

To submit a photo with a ProgressiveSubmission you will need to attach a photo’s url to the progressiveSubmission’s SubmissionFields after uploading the photo using the BVPhotoSubmission.

let jpg: BVPhoto =
  BVPhoto(caption: "Hello?",
  contentType: .review,
  image: image)

let photoSubmission: BVPhotoSubmission =
  BVPhotoSubmission(jpg)
    .configure(config)
    .handler
    { (result: BVConversationsSubmissionResponse<BVPhoto>) in
      guard case .success = result else {
        return
      }
    }

photoSubmission.async()

Answer submission

Submitting an answer is nearly identical to submitting a review or question. Create an instance of BVAnswerSubmission, fill in some parameters, and submit it!

An AnswerSubmission object requires a questionId for which this answer responds to, and answerText, which is the body of the answer.
// create answer submission and fill out with user-input values
let answer = BVAnswerSubmission(questionId: userQuestionId, answerText: userAnswerText)
answer.userNickname = userNickname // "Samantha55"
answer.userId = userId             // user's external ID
answer.userEmail = userEmail       // "test@test.com"
answer.agreedToTermsAndConditions = true

// submit the answer 
  answer.submit({ (answerSubmission: BVSubmissionResponse<BVSubmittedAnswer>) in 
  // answer submitted successfully! 
}, failure: { (errors: [Error]) in 
  // handle failure appropriately 
}) 
// create answer submission and fill out with user-input values
BVAnswerSubmission* answer = [[BVAnswerSubmission alloc] initWithQuestionId:userQuestionId answerText:userAnswerText];
answer.userNickname = userNickname; // "Samantha55"
answer.userId = userId;             // user's external ID
answer.userEmail = userEmail;       // "test@test.com"
answer.agreedToTermsAndConditions = [NSNumber numberWithBool:YES];

 // submit the answer 
[answer submit:^(BVSubmissionResponse<BVSubmittedAnswer *> * _Nonnull response) { 
  // answer submitted successfully! 
} failure:^(NSArray<NSError *> * _Nonnull errors) { 
    // handle failure appropriately 
}]; 
    let answer: BVAnswer = BVAnswer(questionId: userQuestionId, answerText: userAnswerText) 
    guard let answerSubmission = BVAnswerSubmission(answer) else { 
        return nil 
    }     
    (answerSubmission 
      <+> .nickname(userNickname) 
      <+> .email(userEmail) 
      <+> .identifier(userId) 
      <+> .agree(true)) 
    .configure(configuration) 
    .handler { result in 
        if case let .failure(errors) = result { 
         // handle failure appropriately 
          return 
        } 
        guard case let .success(meta, _) = result else { 
          return 
        } 
        // answer submitted successfully! 
    } 
    // submit the answer 
    answerSubmission.async() 
      

Review comment submission

Submitting a review comment is as easy as creating a BVCommentSubmission object with the default initializer and filling out appropriate properties on the BVCommentSubmission object. Look at the sample below for some starter code.

let commentText = "I love comments! They are just the most! Seriously!"
let commentTitle = "Best Comment Title Ever!"
let commentRequest = BVCommentSubmission(reviewId: "192548", withCommentText: commentText)

commentRequest.action = .preview

//commentRequest.fingerPrint = // the iovation fingerprint would go here...
commentRequest.campaignId = "BV_COMMENT_CAMPAIGN_ID"
commentRequest.commentTitle = commentTitle
commentRequest.locale = "en_US"
commentRequest.sendEmailAlertWhenPublished = true
commentRequest.userNickname = "UserNickname"
commentRequest.userId = "UserId"
commentRequest.userEmail = "developer@bazaarvoice.com"
commentRequest.agreedToTermsAndConditions = true

// Some PRR clients may support adding photos, check your configuration
//  if let photo = UIImage(named: "puppy"){
//    commentRequest.addPhoto(photo, withPhotoCaption: "Review Comment Pupper!")
//  }

commentRequest.submit({ (commentSubmission) in
// success
self.showAlertSuccess(message: "Success Submitting Review Comment!")
}, failure: { (errors) in
// error
self.showAlertError(message: errors.description)
})
NSString *commentText = @"I love comments almost as much as Objective-C! They are just the most! Seriously!";
NSString *commentTitle = @"Comments Can We Written In Objective-C";

BVCommentSubmission *submission = [[BVCommentSubmission alloc] initWithReviewId:@"192550" withCommentText:commentText];

//commentRequest.fingerPrint = // the iovation fingerprint would go here...
submission.action = BVSubmissionActionPreview;
submission.campaignId = @"BV_COMMENT_CAMPAIGN_ID";
submission.commentTitle = commentTitle;
submission.locale = @"en_US";
submission.sendEmailAlertWhenPublished = [NSNumber numberWithBool:YES];
submission.userNickname = @"UserNickname";
submission.userId = @"UserId";
submission.userEmail = @"developer@bazaarvoice.com";
submission.agreedToTermsAndConditions = [NSNumber numberWithBool:YES];

// user added a photo to this review
//[submission addPhoto:[UIImage imageNamed:@"puppy"] withPhotoCaption:@"What a cute pupper!"];

[submission submit:^(BVSubmissionResponse<BVSubmittedComment *> * _Nonnull response) { 
  // success 
  [self showSuccess:@"Success Submitting Feedback!"]; 
} failure:^(NSArray<NSError *> * _Nonnull errors) { 
  // error
  [self showError:errors.description]; 
}]; 
    let commentText = "I love comments! They are just the most! Seriously!" 
    let commentTitle = "Best Comment Title Ever!" 
    let reviewId = "192548" 
    let comment = 
      BVComment( 
        reviewId: reviewId, 
        commentText: commentText, 
        commentTitle: commentTitle) 
    guard let commentSubmission = BVCommentSubmission(comment) else { 
      return 
    } 
    let usLocale: Locale = Locale(identifier: "en_US") 
    (commentSubmission 
      <+> .preview 
      <+> .campaignId("BV_COMMENT_CAMPAIGN_ID") 
      <+> .locale(usLocale) 
      <+> .sendEmailWhenPublished(true) 
      <+> .agree(true) 
      // <+> .fingerprint("") // the iovation fingerprint would go here... 
      <+> .nickname("UserNickname") 
      <+> .identifier("UserId") 
      <+> .email("developer@bazaarvoice.com")) 
      .configure(configuration) 
      .handler { (response: BVConversationsSubmissionResponse<BVComment>) in 
        if case let .failure(errors) = response { 
      // error           
          return 
        } 
        guard case let .success(meta, result) = response else { 
            return 
        } 
    // success 
    } 
    commentSubmission.async() 
      

Feedback submission

Submitting a feedback is the simplest of content submissions. Create an instance of BVFeedbackSubmission, fill out the required parameters, and submit it! You can use the Feedback submission for either Helpfulness votes or for flagging inappropriate content, just set the type with the BVFeedbackType enumerator.

Aa BVFeedbackSubmission object requires a contentId which will correspond to the identifer of the Review, Question, or Answer your client is providing feedback on.
You cannot submit feedback for syndicated content. Make sure to check the IsSyndicated flag before you display your feedback UI.
let feedback = BVFeedbackSubmission(contentId: contentId, 
  with: BVFeedbackContentType.review, 
  with: BVFeedbackType.helpfulness) 

feedback.userId = userId 
feedback.vote = BVFeedbackVote.positive // or .Negative for down vote 

feedback.submit({ (response) in 
  // success 

  // Make sure to disable the submission UI so the user can't submit again. 

}) { (errors) in 
  // error 
  // Ooops, some error. Rollback if needed. 
} 
BVFeedbackSubmission *feedback = [[BVFeedbackSubmission alloc] initWithContentId:contentId withContentType:BVFeedbackContentTypeReview withFeedbackType:BVFeedbackTypeHelpfulness];   
feedback.userId = userId; 
feedback.vote = BVFeedbackVotePositive; 
feedback.action = BVSubmissionActionPreview; 

[feedback submit:^(BVSubmissionResponse<BVSubmittedFeedback *> * _Nonnull response) { 
  // success 
  
  // Make sure to disable the submission UI so the user can't submit again. 
} failure:^(NSArray<NSError *> * _Nonnull errors) { 
  // error 
  // Ooops, some error. Rollback if needed. 
}]; 
      let feedback = 
      BVFeedback.helpfulness( 
        vote: .positive, 
        authorId: authorId, 
        contentId: contentId, 
        contentType: .review) 
    guard let feedbackSubmission = BVFeedbackSubmission(feedback) else { 
      return 
    } 
    (feedbackSubmission <+> .identifier(userId)) 
      .configure(configuration) 
      .handler { (response: BVConversationsSubmissionResponse<BVFeedback>) in 
        if let _ = response.errors { 
      // error 
      // Ooops, some error. Rollback if needed. 
          return 
        } 
        guard case let .success(_, result) = response else { 
          return 
        } 
    // success 
    // Make sure to disable the submission UI so the user can't submit again. 
    } 
    feedbackSubmission.async() 
      

Photo Submission

Submitting a feedback is the simplest of content submissions. Create an instance of BVFeedbackSubmission, fill out the required parameters, and submit it! You can use the Feedback submission for either Helpfulness votes or for flagging inappropriate content, just set the type with the BVFeedbackType enumerator.

Aa BVFeedbackSubmission object requires a contentId which will correspond to the identifer of the Review, Question, or Answer your client is providing feedback on.
You cannot submit feedback for syndicated content. Make sure to check the IsSyndicated flag before you display your feedback UI.
let
BV

Generic form field options

All available fields are detailed in BVReviewSubmission.h and further in Bazaarvoice's API Documentation. Required fields, and specific rules per field ("reviewText must be longer than X characters") is dependent on your specific deployment setup.