Skip to content
:docs

Advanced settings

Learn which features you can implement in Feed and how to configure them.

To change or implement placement features, use the SDK's default UI or implement your own classes. The diagram below shows the main Feed features.

Integrate Feed as a child view controller

In addition to the standard present and push integration methods, BuzzAd SDK for iOS supports integrating Feed as a child view controller.

To integrate Feed this way, add the child view controller to your parent view controller.

The following example adds Feed as a child view controller.

Swift
import BuzzAdBenefit

final class ContainerViewController: UIViewController {
  let buzzAdFeed = BZVBuzzAdFeed { builder in }

  override func viewDidLoad() {
    super.viewDidLoad()

    displayContentViewController(buzzAdFeed.viewController)
  }

  private func displayContentViewController(_ contentViewController: UIViewController) {
    addChild(contentViewController)
    contentViewController.view.frame = view.bounds
    view.addSubview(contentViewController.view)
    contentViewController.didMove(toParent: self)
  }
}

Ad categories

Feed uses tabs and filters to group ads by type. Users can focus on the types they want to participate in, improving the experience and ad efficiency.

Category settings can be changed without editing code or redeploying your app. Contact your Buzzvil representative to change them.

Ad category tabs and filters

Configure the number of tabs, their names and their ad types. Up to three tabs are supported. The defaults are Ad rewards, which includes all non-shopping ad types, and Shopping rewards, which includes shopping ads.

Tabs can contain impression-based, action-based, video, social media or shopping ads. Each tab can include multiple types, except shopping ads, which cannot share a tab with other types.

Tabs with multiple ad types show filters such as “Click” and “Participate” to narrow the results.

Infinite scrolling

Feed's infinite scroll automatically loads more ads when users reach the end of the current ad list. It is enabled by default. You can enable or disable it without changing your app's code or releasing an update; contact your Buzzvil representative to change the setting.

Add entry points to your app UI

Implement your own views in icons, buttons, banners or other UI elements to create entry points into Feed.

See the diagram below for example UI components. The sample app includes code for several custom entry points.

Prerequisites

Add an entry point

You can add a Feed entry point to a view controller. Implement a custom view that subclasses BZVFeedEntryView and add it as a subview.

Implement an entry point in code

The following example creates a custom view that subclasses BZVFeedEntryView and adds it as a subview of the view controller.

  1. Define a subclass of BZVFeedEntryView and implement its layout.
Swift
import BuzzAdBenefit

final class CustomFeedEntryView: BZVFeedEntryView {
  let customSubview1 = UIView(frame: .zero)
  let customSubview2 = UIView(frame: .zero)

  required init?(coder: NSCoder) {
    super.init(coder: coder)
    setupView()
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
  }

  private func setupView() {
    // subview 초기화 및 LayoutConstraint 설정
    ...생략...

    // 클릭이 가능한 영역을 지정합니다.
    clickableViews = [customSubview1, customSubview2]
  }
}
  1. Initialize and use your subclass (CustomFeedEntryView) of BZVFeedEntryView.
Swift
import UIKit

final class ViewController: UIViewController {
  private lazy var customFeedEntryView: CustomFeedEntryView = {
    let view = CustomFeedEntryView(frame: .zero)
    return view
  }()

  override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(customFeedEntryView)

    // LayoutConstraint 설정
    ...
  }
}

Track user interactions

After creating an entry point, add setEntryName to track view impressions and user clicks. To use this feature, share the details of setEntryName with your Buzzvil representative.

Swift
import UIKit

final class ViewController: UIViewController {
  private lazy var customFeedEntryView: CustomFeedEntryView = {
    let view = CustomFeedEntryView(frame: .zero)
    // 뷰에 대한 사용자 반응을 추적합니다.
    view.setEntryName("your_custom_entry_point_1")
    return view
  }()
  
  override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(customFeedEntryView)

    // LayoutConstraint 설정
    ...
  }
}

Display available points

Preview the available points, as shown below, to encourage users who have not yet entered Feed to participate.

Follow these steps to show available points in advance.

  1. Call [BZVBuzzAdFeed load] to allocate Feed ads.
  2. On success, the onSuccess callback is invoked. - See Load and display Feed ads.
  3. In the onSuccess callback, call buzzAdFeed.availableRewards to retrieve the total available reward amount.
  4. Update your view with that amount.

The following example refreshes Feed and updates the view whenever viewDidLoad runs.

Swift
final class ViewController: UIViewController {

  override func viewDidLoad() {
    ...생략...
    
    customFeedEntryView.buzzAdFeed.load {
      self.updateFeedEntryView(reward: self.customFeedEntryView.buzzAdFeed.availableRewards)
    } onFailure: { _ in
      self.updateFeedEntryView(reward: 0)
    }
  }
  
  private func updateFeedEntryView(reward: Int) {
    // 적립 가능한 포인트 안내 문구 설정
  }
}

Implement a custom header

You can use the Feed header area as needed—for example, to explain the placement or show the rewards available to earn.

The following example changes the header.

Create a subclass of BZVFeedHeaderViewHolder and implement your custom header view. Register it in headerViewHolderClass of BZVFeedConfig.

Swift
final class CustomHeaderViewHolder: BZVFeedHeaderViewHolder {
  let headerLabel = UILabel(frame: .zero)

  override class func desiredHeight() -> CGFloat {
    return 100.0
  }

  required init?(coder: NSCoder) {
    super.init(coder: coder)
    setUpView()
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
    setUpView()
  }

  func setUpView() {
    addSubview(headerLabel)

    // LayoutConstraint 설정
    ...
  }
  
  override func availableRewardDidUpdate(_ reward: Int) {
    headerLabel.text = "리워드 \(reward)원"
  }
}
Swift
let config = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.headerViewHolderClass = CustomHeaderViewHolder.self
}

Implement a custom base reward notification

Users receive points periodically when entering Feed, even without participating in an ad. Customize the base reward notification to improve the experience.

The following example implements a custom base reward notification.

  1. Create a class that subclasses BZVFeedBaseRewardViewHolder.
Swift
final class CustomFeedBaseRewardViewHolder: BZVFeedBaseRewardViewHolder {
  let baseRewardLabel = UILabel(frame: .zero)
  
  override class func desiredHeight() -> CGFloat {
    return 100.0
  }
  
  required init?(coder: NSCoder) {
    super.init(coder: coder)
    setUpView()
  }
  
  override init(frame: CGRect) {
    super.init(frame: frame)
    setUpView()
  }
  
  func setUpView() {
    addSubview(baseRewardLabel)
    
    // LayoutConstraint 설정
    ...
  }
  
  override func didUpdateBaseReward(_ baseReward: Int) {
    baseRewardLabel.text = "Received \(baseReward) points"
  }
}
  1. Set the CustomFeedBaseRewardViewHolder created in the previous step on BZVFeedConfig.
Swift
let config = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.baseRewardViewHolderClass = CustomFeedBaseRewardViewHolder.self
}

Implement a custom ad design

BuzzAd SDK for iOS provides standard ads and shopping reward ads.

  • Standard ads: All ad types other than shopping ads.
  • Shopping reward ads: Users who make a purchase through an ad earn points equivalent to a percentage of the purchase amount.

Both types contain multiple elements that describe the ad. See the table below for the elements and UI of standard ads and shopping reward ads.

Ad typeComponentDescription
Shared: standard and shoppingAd title (required)The ad title. A maximum of 10 characters is recommended. You may truncate part of the text with an ellipsis as needed, regardless of length.
Ad creative (required)
  • The ad image, video or other creative. Preserve its aspect ratio.
  • Display it using BZVMediaView.
  • Size: 1,200 × 627 px.
  • You may add padding. Contact your Buzzvil representative for details.
Ad description (required)A detailed ad description. A maximum of 40 characters is recommended. You may truncate part of the text with an ellipsis as needed, regardless of length.
Advertiser icon (required)
  • The advertiser's icon image. Preserve its aspect ratio.
  • Size: 80 × 80 px.
CTA button (required)
  • A button encouraging ad participation. A maximum of 7 characters is recommended. You may truncate part of the text with an ellipsis as needed, regardless of length.
  • Display it using BZVDefaultCtaView.

  • ✏️  Note
    See Implement a custom CTA button to change the design.
Ad disclosure (recommended)Text identifying the content as advertising, such as 광고, ad, 스폰서 or Sponsored.
Shopping rewardsOriginalPrice View (recommended)Displays the original product price.
Price View (recommended)Displays the discounted product price.
DiscountRate View (recommended)Displays the discount rate. Calculate it from the original and discounted prices.

Implement a custom standard ad design

Follow these steps to customize standard ads.

  1. Implement a subclass of BZVFeedAdViewHolder for standard ads.
  • Add BZVNativeAdView, BZVMediaView and BZVDefaultCtaView as subviews.
  • In renderAd, use BZVNativeAdViewBinder to bind ad data (NativeAd) to the CustomFeedAdViewHolder you created.
Swift
import UIKit
import BuzzAdBenefit

final class CustomFeedAdViewHolder: BZVFeedAdViewHolder {
  let nativeAdView = BZVNativeAdView(frame: .zero)
  let mediaView = BZVMediaView(frame: .zero)
  let iconImageView = UIImageView(frame: .zero)
  let titleLabel = UILabel(frame: .zero)
  let descriptionLabel = UILabel(frame: .zero)
  let ctaView = BZVDefaultCtaView(frame: .zero)
  lazy var viewBinder = BZVNativeAdViewBinder { builder in
    builder.nativeAdView = self.nativeAdView
    builder.mediaView = self.mediaView
    builder.iconImageView = self.iconImageView
    builder.titleLabel = self.titleLabel
    builder.descriptionLabel = self.descriptionLabel
    builder.ctaView = self.ctaView
  }

  required init?(coder: NSCoder) {
    super.init(coder: coder)
    setUpView()
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
    setUpView()
  }

  func setUpView() {
    addSubview(nativeAdView)
    nativeAdView.addSubview(mediaView)
    nativeAdView.addSubview(iconImageView)
    nativeAdView.addSubview(titleLabel)
    nativeAdView.addSubview(descriptionLabel)
    nativeAdView.addSubview(ctaView)

    // LayoutConstraint 설정
    ...
  }

  override func renderAd(_ ad: BZVNativeAd) {
    viewBinder.bind(with: ad)
  }
}

Optionally receive ad callbacks through BZVNativeAdEventDelegate.

Swift
import UIKit
import BuzzAdBenefit

final class CustomFeedAdViewHolder: BZVFeedAdViewHolder, BZVNativeAdEventDelegate {

  override func renderAd(_ ad: BZVNativeAd) {
    viewBinder.bind(with: ad)
    ad.delegate = self
  }
  
  // MARK: BZVNativeAdEventDelegate
  func didImpress(_ nativeAd: BZVNativeAd) {
  }

  func didClick(_ nativeAd: BZVNativeAd) {
  }

  func didRequestReward(for nativeAd: BZVNativeAd) {
  }

  func didReward(for nativeAd: BZVNativeAd, with result: BZVRewardResult) {
  }

  func didParticipateAd(_ nativeAd: BZVNativeAd) {
  }
}
  1. Set your CustomFeedAdViewHolder as the ad ViewHolder in BZVFeedConfig.
Swift
let config = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.adViewHolderClass = CustomFeedAdViewHolder.self
}

Implement a custom shopping ad design

Follow these steps to customize shopping ads.

  1. Implement a subclass of BZVFeedAdViewHolder following Implement a custom standard ad design.
  • Add priceLabel, originalPriceLabel and discountPercentageLabel to the standard ad layout.
Swift
import UIKit
import BuzzAdBenefit

final class CustomFeedCpsAdViewHolder: BZVFeedAdViewHolder {
  let nativeAdView = BZVNativeAdView(frame: .zero)
  let mediaView = BZVMediaView(frame: .zero)
  let iconImageView = UIImageView(frame: .zero)
  let titleLabel = UILabel(frame: .zero)
  let descriptionLabel = UILabel(frame: .zero)
  let ctaView = BZVDefaultCtaView(frame: .zero)
  let priceLabel = UILabel(frame: .zero)
  let originalPriceLabel = UILabel(frame: .zero)
  let discountRateLabel = UILabel(frame: .zero)
  lazy var viewBinder = BZVNativeAdViewBinder { builder in
    builder.nativeAdView = self.nativeAdView
    builder.mediaView = self.mediaView
    builder.iconImageView = self.iconImageView
    builder.titleLabel = self.titleLabel
    builder.descriptionLabel = self.descriptionLabel
    builder.ctaView = self.ctaView
    // 부가 기능: 텍스트를 클릭할 수 있도록 설정합니다.
    builder.clickableViews = [
      self.mediaView,
      self.ctaView,
      self.priceLabel,
      self.originalPriceLabel,
      self.discountRateLabel,
    ]
  }

  required init?(coder: NSCoder) {
    super.init(coder: coder)
    setUpView()
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
    setUpView()
  }

  private func setUpView() {
    // 광고 레이아웃 컴포넌트를 생성합니다.
     ...생략...
    nativeAdView.addSubview(priceLabel)
    nativeAdView.addSubview(originalPriceLabel)
    nativeAdView.addSubview(discountRateLabel)

    // LayoutConstraint 설정
    ...생략...
  }

  override func renderAd(_ ad: BZVNativeAd) {
    viewBinder.bind(with: ad)

    let product = ad.product
    if product.discountedPrice != 0 {
      // 할인이 있는 쇼핑 광고
      priceLabel.text = NSNumber(value: product.discountedPrice).formattedString()
      originalPriceLabel.text = NSNumber(value: product.price).formattedString()
      let discountRate = (1 - product.discountedPrice / product.price) * 100
      discountRateLabel.text = String(format: "%d%%", Int(discountRate))
    } else {
      // 할인이 없는 쇼핑 광고
      priceLabel.text = NSNumber(value: product.discountedPrice).formattedString()
      originalPriceLabel.text = NSNumber(value: product.price).formattedString()
      discountRateLabel.text = "0%%"
    }
  }
}

extension NSNumber {
  func formattedString() -> String? {
    let numberFormatter = NumberFormatter()
    numberFormatter.numberStyle = .decimal
    return numberFormatter.string(from: self)
  }
}
  1. Set the CustomFeedAdViewHolder from the previous step as the shopping ad ViewHolder in BZVFeedConfig.
Swift
let config = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.cpsAdViewHolderClass = CustomCpsAdViewHolder.self
}

Implement a custom CTA button

You can implement your own CTA button instead of using the default UI provided by BuzzAd SDK for iOS.

To implement your own CTA button, create a subclass of UIView that conforms to the CtaViewProtocol protocol.

The following example creates a CTA View class using UIStackView.

Swift
import UIKit
import BuzzAdBenefit

final class CustomCtaView: UIStackView, BZVCtaViewProtocol {
  let rewardImageView = UIImageView(frame: .zero)
  let rewardLabel = UILabel(frame: .zero)
  let ctaLabel = UILabel(frame: .zero)

  required init(coder: NSCoder) {
    super.init(coder: coder)
    setUpView()
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
    setUpView()
  }

  private func setUpView() {
    addArrangedSubview(rewardImageView)
    addArrangedSubview(rewardLabel)
    addArrangedSubview(ctaLabel)
  }

  // MARK: BZVCtaViewProtocol
  func renderRewardNotAvailableViewState(withCtaText ctaText: String) {
    // 리워드가 없는 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
    rewardImageView.isHidden = true
    rewardLabel.isHidden = true
    ctaLabel.text = ctaText
  }

  func renderRewardAvailableViewState(withCtaText ctaText: String, reward: Int) {
    // 리워드가 있는 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
    rewardImageView.isHidden = false
    rewardLabel.isHidden = false

    rewardImageView.image = UIImage(named: "YOUR_REWARD_IMAGE")
    rewardLabel.text = "+\(reward)"
    ctaLabel.text = ctaText
  }

  func renderParticipatingViewState(withCtaText ctaText: String) {
    // 참여 확인 중인 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
    rewardImageView.isHidden = true
    rewardLabel.isHidden = true
    ctaLabel.text = "YOUR_PARTICIPATING_TEXT"
  }

  func renderParticipatedViewState(withCtaText ctaText: String) {
    // 참여 완료한 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
    rewardImageView.isHidden = false
    rewardLabel.isHidden = true

    rewardImageView.image = UIImage(named: "YOUR_PARTICIPATED_IMAGE")
    ctaLabel.text = "YOUR_PARTICIPATED_TEXT"
  }
}

Implement a custom no-ads screen

If no ads are available when Feed opens, a no-ads UI appears. You can replace it with your own design.

The following example customizes the no-ads message.

Create a class that subclasses BZVFeedErrorViewHolder, then assign it to the errorViewHolderClass property of BZVFeedConfig. Optionally, override updateViewWithError to update the UI based on the error.

Swift
import UIKit
import BuzzAdBenefit

final class CustomFeedErrorViewHolder: BZVFeedErrorViewHolder {
  let imageView = UIImageView(image: UIImage(named: "YOUR_ERROR_IMAGE_NAME"))

  required init?(coder: NSCoder) {
    super.init(coder: coder)
    setupView()
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
  }

  private func setupView() {
    addSubview(imageView)

    // LayoutConstraint 설정
    ...
  }

  override func updateViewWithError(_ error: Error) {
    // error에 따라 UI를 업데이트 할 수 있는 코드 작성
  }
}

let config = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.errorViewHolderClass = CustomFeedErrorViewHolder.self
}

Tracking authorization

BuzzAd SDK for iOS provides features for requesting App Tracking Transparency authorization on iOS 14 and later. Feed can display a dialog and a banner to help users grant tracking permission.

Display the tracking authorization dialog when Feed opens

When enabled, the dialog appears when users on iOS 14 or later enter Feed without having granted tracking permission.

The following example displays the tracking authorization dialog when the user opens Feed.

Swift
let config = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.shouldShowAppTrackingTransparencyDialog = true
}

Add a tracking authorization information banner

You can display a banner at the top of Feed explaining opportunities to earn more rewards and encouraging users to allow tracking. It appears only for users who have denied permission.

The following example adds the tracking authorization information banner.

Swift
let config = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.shouldShowAppTrackingTransparencyGuideBanner = true
}

You can also add a property to the Info.plist file to change the URL opened when the banner is clicked.

XML
<key>BuzzAdAppTrackingTransparencyLandingURL</key>
<string>YOUR_ATT_DESCRIPTION_URL</string>

Check the ad type

The BuzzAd Android SDK provides APIs to identify ad types so you can offer different rewards or experiences for impression-based, action-based and other ads. See Check the ad type in Frequently asked questions.

UI for consent to share personal information with third parties

BuzzAd SDK for iOS provides a UI for obtaining consent to share personal information.

The previous function has been deprecated. For BuzzAd iOS v3.21.x and later, we recommend removing the code below. The setting can be controlled remotely without this code.

  • BuzzAdBenefit.privacyPolicyManager
  • PrivacyPolicyManager.presentConsentForm()
  • PrivacyPolicyManager.grantConsent()
  • PrivacyPolicyManager.revokeConsent()
  • PrivacyPolicyManager.isConsentGranted()