Content Submission

This documentation explains the mechanics of submitting user-generated content (UGC) to Bazaarvoice using the Mobile SDK.

Introduction

The BVSDK makes it easy to upload user-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 user-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.

📘

A BVReviewSubmission object requires a reviewTitle, reviewText, rating, and productId (for which this review corresponds to).

Objective-C SDK

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;       // "[email protected]"
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 = 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       // "[email protected]"
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
})

Swift SDK

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
    }
  }

Progressive Submission

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

Objective-C SDK

Objective-C

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 is 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
}];

Swift

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
}

Swift SDK

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.

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.

📘

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 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()

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.

Objective-C SDK

// 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;          // "[email protected]"
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
}];
// 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       // "[email protected]"
question.agreedToTermsAndConditions  = true
 
// submit the question
question.submit({ (questionSubmission: BVSubmissionResponse<BVSubmittedQuestion>) in
  // question submitted successfully!
}, failure: { (errors: [Error]) in
 // handle failure appropriately
})

Swift SDK

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()

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.

Objective-C SDK

// 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;       // "[email protected]"
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
}];
// 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       // "[email protected]"
answer.agreedToTermsAndConditions = true
 
// submit the answer
  answer.submit({ (answerSubmission: BVSubmissionResponse<BVSubmittedAnswer>) in
  // answer submitted successfully!
}, failure: { (errors: [Error]) in
  // handle failure appropriately
})

Swift SDK

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.

Objective-C SDK

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 = @"[email protected]";
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 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 = "[email protected]"
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)
})

Swift SDK

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.

📘

A BVFeedbackSubmission object requires a contentId which will correspond to the identifier 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.

Objective-C SDK

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 = 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.
}

Swift SDK

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.