Mobile SDKs: Integrate Bazaarvoice into your native Android and iOS apps.
Content Submission
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
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.
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
.
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.
// The review is the object of BVReviewSubmission. review.submit({ (reviewSubmission) in // formFieldIdentifier is the name of the key that must be used for submission // formField contains metadata reviewSubmission.formFields // Here you will get the formFields }, failure: { (errors) in // handle error })
guard let reviewSubmission = BVReviewSubmission(productId: "test1") else { return } reviewSubmission .configure(config) .add(.form) .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 { let formFieldIdentifier = formField.identifier // formFieldIdentifier is the name of the key that must be used for submission 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.
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. Review body. Review Body. !!!", reviewTitle: "Review title goes here", reviewRating: 4) guard let reviewSubmission = BVReviewSubmission(review) else { return } reviewSubmission .add(.nickname("Nick")) .add(.additional(name: "DateOfUserExperience", value: "2021-04-03")) .add(.agree(true)) .configure(config) .add(.submit) .handler { result in if case let .failure(errors) = result { errors.forEach { print($0) } return } guard case let .success(meta, _) = result else { return } }
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!
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: "Does it have fingerprint sensor?", // questionSummary: "Fingerprint Sensor", isUserAnonymous: false) guard let questionSubmission = BVQuestionSubmission(question) else { return } questionSubmission .add(.nickname("Nick")) .add(.agree(true)) .add(.submit) questionSubmission .configure(config) .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.
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.
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 * 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 *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.
var encodedUAS = "926e8604e6094ad98ec63c6eeb8d9e1a5cd47d68b141a8b0a5e206dc7e610504646174653d3230323131323037267573657269643d454d30303126456d61696c416464726573733d6162697368656b68732e6b616d617468253242546573742534306266f6963652ef6d" let multiProduct = BVMultiProduct( productIds: ["product1", "product2"], locale: "en_US", userToken: encodedUAS, userId: nil) guard let initiateMultiproductSubmission = BVMultiProductQuery(multiProduct) else { return } initiateMultiproductSubmission .configure(config) .handler { response in if case let .failure(errors) = response, let error = errors.first { print("Fail") return } guard case let .success(_, products) = response else { return } for product in products.productFormData! { print(product.review?.productExternalId) print(product.submissionSessionToken) } } initiateMultiproductSubmission.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.
var submissionFields = BVProgressiveReviewFields() submissionFields.rating = 4 submissionFields.title = "my favorite product ever!" submissionFields.reviewtext = "favorite product review body favorite product review body favorite product review body" submissionFields.agreedToTerms = true var reviewSubmission = BVProgressiveReview( productId: "product1", submissionFields: submissionFields) reviewSubmission.isPreview = true reviewSubmission.submissionSessionToken = "sessionToken" reviewSubmission.locale = "en_US" reviewSubmission.userToken = encodedUAS 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) } print("Success") } 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!
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: "1642264", answerText: "Yes. Charger is included in the box.") guard let answerSubmission = BVAnswerSubmission(answer) else { return } answerSubmission .add(.nickname("Nick")) .add(.agree(true)) .add(.submit) .configure(config) .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 comment = BVComment( reviewId: "20134832", commentText: "Thanks for posting this review!", commentTitle: "Nice Review.") guard let commentSubmission = BVCommentSubmission(comment) else { return } commentSubmission .add(.submit) .add(.nickname("Nick")) .configure(config) .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.
BVFeedbackSubmission
object requires a contentId
which will correspond to the identifer of the Review, Question, or Answer your client is providing feedback on.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: "reviewAuthor", contentId: "reviewId", contentType: .review) guard let feedbackSubmission = BVFeedbackSubmission(feedback) else { return } feedbackSubmission .configure(config) .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()
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.