Skip to content
:docs

UI configuration

Global theme

You can customize the theme of the Buzzvil SDK's default UI, including colors and icon images for ad placements and CTAs.

Primary color

Change the primary color of key SDK UI elements across all placements, including dialog buttons and bottom sheet confirmation buttons.

Add color resources as shown below to change the primary color.

Swift
import BuzzvilSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        let config = ...

        // BuzzBenefit.initialize()를 호출하기 전에  GlobalTheme을 설정합니다.
        let theme = BuzzBenefitTheme { builder in
          builder.primaryColor = YOUR_PRIMARY_COLOR
          builder.primaryLightColor = YOUR_PRIMARY_LIGHT_COLOR
        }

        BuzzBenefit.shared.setGlobalTheme(theme)

        BuzzBenefit.shared.initialize(with: config)
        return true
    }
}

Reward icon

Customize icons in SDK UI elements such as CTA buttons.

The following example adds rewardIcon to BuzzBenefitTheme to change the reward icon. The table lists the UI controlled by each property.

PropertyConfigurable UI
rewardIconAll placements: CTA reward icon., BenefitHub: profile input banner reward icon., BenefitHub: Pop opt-in button icon.
participatedIconAll placements: CTA view.
Swift
import BuzzvilSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        let config = ...

        // BuzzBenefit.initialize()를 호출하기 전에  GlobalTheme을 설정합니다.
        let theme = BuzzBenefitTheme { builder in
          builder.rewardIcon = YOUR_REWARD_ICON
          builder.participatedIcon = YOUR_PARTICIPATED_ICON
        }
        BuzzBenefit.shared.setGlobalTheme(theme)

        BuzzBenefit.shared.initialize(with: config)
        return true
    }
}

Implement a custom CTA button

Implement custom CTA buttons instead of the default UI. You can use them in BenefitHub and Native.

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 BuzzvilSDK

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

Apply the custom CTA button to GlobalTheme

Add ctaViewClass to BuzzBenefitTheme to apply your custom CTA button.

Swift
import BuzzvilSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        let config = ...

        // BuzzBenefit.initialize()를 호출하기 전에  GlobalTheme을 설정합니다.
        let theme = BuzzBenefitTheme { builder in
          // ...
          builder.ctaViewClass = CustomCtaView.self
        }

        BuzzBenefit.shared.setGlobalTheme(theme)

        // ...
        return true
    }
}

Native

Native overlay UI

Configure overlay images and text in Buzzvil Dash Admin.


Follow these steps to configure Native Overlay UI.

  1. Open Buzzvil Dash Admin (https://dashboard.buzzvil.com/).
  2. Find and select your app in Inventory Manager, then open Entry Point Contents in the left menu.
  3. Select “Native Overlay” from the Entry point type dropdown.
  4. Enable Customization for each overlay type.
  5. Add your images and UI strings.
    • Preview changes in real time.
    • Unconfigured overlays use Buzzvil's default UI.
  • Supported image and UI text specifications:
    • Image formats: PNG, JPG, JSON (Lottie)
    • File size: Up to 2 MB - Image ratio: 312 × 212, width × height.
    • UI text: Up to 20 characters, including spaces, across two lines
  1. Click Save in the upper-right corner.

BenefitHub

This section explains how to change the design of the UI provided by the Buzzvil SDK.

Lucky Box

Customize Lucky Box strings and images without an SDK patch. Send the settings and content you want to change to help@buzzvil.com.

ItemDescription
Promotion nameTitle at the top of Lucky Box details., Maximum 15 characters, including spaces., Default meaning: “Today's gift box.”
Entry point before and after participationIcon and text shown in BenefitHub., Default meanings: “Today's gift box” before participation; “See you tomorrow!” afterward.
Participation progress iconsIcons for days 1–5: not started, completed, recovery and streak bonus., 24 × 24, width × height., PNG, JPG or JSON (Lottie)., Maximum 2 MB.
Lucky Box CTA before and after participationThe CTA users tap to participate., Default meanings: “Open your gift box” before participation; “Completed! See you tomorrow” afterward.
Images before and after participationImage above the Lucky Box CTA., 100 × 100, width × height., PNG, JPG or JSON (Lottie)., Maximum 2 MB.
Additional reward bannerA CPC-only banner below the Lucky Box banner after participation., 24 × 24, width × height., PNG, JPG or JSON (Lottie)., Maximum 2 MB., Default text meaning: “Tap for a bonus.”
Daily reward amountLucky Box reward granted once per day., Default: 1.
Streak reward amountAdditional reward granted on day five after five consecutive days of participation., Default: 2.
Streak completion textText announcing the streak reward., Default meaning: “You completed the streak!”
Streak completion text colorColor of the streak completion text., Format: hex., Default: FFFFFF.
Streak completion iconIcon announcing the streak reward., 80 × 80, width × height., PNG, JPG or JSON (Lottie)., Maximum 2 MB.
Streak completion effectsEffect image surrounding the streak completion icon., 375 × 375, width × height., PNG, JPG or JSON (Lottie)., Maximum 2 MB.
NoticesInformation and disclaimers about Lucky Box operation and reward policies., You can edit the reward amount guidance.

Mission Pack

Customize MissionPack strings and images without an SDK patch. Send the settings and content you want to change to help@buzzvil.com.

ItemDetailDescription
BenefitHub entry pointTitleSee the BenefitHub entry point image showing the title and icon.
BenefitHub entry pointIconSee the BenefitHub entry point image showing the title and icon.
BackgroundColorApply element colors to BuzzBenefitTheme through primaryColor.
BackgroundGradientApply backgroundGradientColors as the background color in BuzzBenefitTheme. See “Configure the MissionPack background gradient.”
Promotion titleText-
Mission bonusReward percentageGrants n% of the rewards from completed missions as a bonus., Fractional bonus amounts are rounded to the nearest integer.
Mission bonus CTAText-
Mission in progressTitle-
Mission in progressIconSupports PNG, JPG and JSON (Lottie).
Mission in progressDescriptionSee the “UI and mission settings” image., The bonus percentage follows the configured reward percentage.
Mission in progressIn-progress CTAMaximum 6 characters.
Mission in progressCompletion CTAMaximum 6 characters.
Completed participationTitle-
Mission configurationMission title-
Mission configurationCriteriarevenue type: CPI, CPE, CPQ, CPQLITE, CPCQUIZ, CPYoutube, CPInsta, CPK, CPTiktok, CPL, CPYLike, CPNstore., ad type (Hub filters): click, action, social media, content, shopping and video rewards., event type + resource type: event features such as Lucky Box.
Mission configurationProgress per missionNumber of ads in the mission.
Lucky Box entry pointCTAMaximum 6 characters.
Notices-The default text automatically uses the configured mission bonus percentage.
Performance tracking unit-
  • Records completed ads from MissionPack's mission feed, including revenue and cost in Inventory Manager Analytics.
  • Determines the mission feed's unit settings.With an existing Hub: its Unit ID is applied automatically., Without an existing Hub, or when operating as SIS: a new Unit ID is required.
  • ✅  Important
    Each MissionPack can have only one performance tracking unit.
Participation credit unit-A unit whose ad participation counts toward MissionPack missions., ✅  Important
Each MissionPack can have one or more participation credit units.

Configure the MissionPack background gradient

Swift
import BuzzvilSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        let config = ...

        // BuzzBenefit.initialize()를 호출하기 전에  GlobalTheme을 설정합니다.
        let theme = BuzzBenefitTheme { builder in
          // ...
          builder.backgroundGradientColors = [YOUR_GRADIENT_UICOLOR, ...]
        }

        BuzzBenefit.shared.setGlobalTheme(theme)

        // ...
        return true
    }
}

Navigation bar

You can change the text in BenefitHub's navigation bar or implement your own navigation bar.

Change navigation bar text

You can change navigation bar UI strings.

Swift
let feedTheme = BZVFeedTheme { builder in
  builder.navigationBarTitle = "YOUR_TITLE"
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)

Implement a custom navigation bar

See Integrate BenefitHub as a child view controller to implement your own navigation bar.

Header

Use BenefitHub's header for your own content, such as an explanation of the placement or the available reward amount.

The following example changes the header.

Create a subclass of BZVFeedHeaderView and implement your custom header view. Register it in headerViewClass of BZVFeedConfig.

Swift
import UIKit
import BuzzvilSDK

final class CustomFeedHeaderView: BZVFeedHeaderView {
  let headerLabel = UILabel(frame: .zero)

  override class func desiredHeight(_ width: CGFloat) -> CGFloat {
    return 60
  }

  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 feedConfig = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.headerViewClass = CustomFeedHeaderView.self
}

Ad category filters

Ad category filters use monochrome colors by default. You can change them to follow the primary color.

Swift
let feedTheme = BZVFeedTheme { builder in
  builder.usePrimaryColorInFilter = true
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)

Ad design

Buzzvil SDK provides standard ads and shopping ads.

  • Standard ads: All ad types other than shopping ads.
  • Shopping ads: Users receive a percentage of their purchase amount as points after buying through the ad.

Both types contain multiple elements for displaying the ad. Their components and UI requirements are listed below.

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.
Clickable areas (required)Defines which areas of the ad respond to clicks.
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 BZVFeedAdView for standard ads.
  • Add BZVNativeAdView, BZVMediaView and BZVDefaultCtaView as subviews.
  • In renderAd, use BZVNativeAdViewBinder to bind ad data (NativeAd) to the CustomFeedAdView you created.
Swift
import UIKit
import BuzzvilSDK

final class CustomFeedAdView: BZVFeedAdView {
  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
    builder.clickableViews = [
      self.mediaView,
      self.ctaView
    ]
  }

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

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

  override class func desiredHeight(_ width: CGFloat) -> CGFloat {
    return width * 0.8
  }

  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 BuzzvilSDK

final class CustomFeedAdView: BZVFeedAdView, 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 CustomFeedAdView as the ad ViewHolder in BZVFeedConfig.
Swift
let feedConfig = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.adViewClass = CustomFeedAdView.self
}

Implement a custom shopping ad design

Follow these steps to customize shopping ads.

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

final class CustomFeedCpsAdView: BZVFeedAdView {
  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,
    ]
  }

  override class func desiredHeight(_ width: CGFloat) -> CGFloat {
    return 350
  }

  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 CustomFeedAdView from the previous step as the shopping ad ViewHolder in BZVFeedConfig.
Swift
let config = BZVFeedConfig { builder in
  builder.unitId = "YOUR_FEED_UNIT_ID"
  builder.cpsAdViewClass = CustomFeedCpsAdView.self
}

No-ads UI

Users can retry up to three times when no ads are available. Customize the UI strings and images for each attempt.

Retry attemptTitleContentButton
Initial attempt미션을 준비 중이에요다시 미션을 불러와서 포인트를 모아보시겠어요?미션 불러오기
First retry미션을 준비 중이에요미션을 로딩 중이에요. 잠시 후 다시 시도해주세요.다시 불러오기
Second retry미션을 준비 중이에요미션 준비에 시간이 걸리고 있습니다. 잠시 후 다시 시도해주세요.한번 더 불러오기
Third retry (last)미션을 준비 중이에요All filter: 지금은 참여 가능한 미션이 없습니다. 잠시 후 다시 방문해주세요.
Other filters: 지금은 참여 가능한 미션이 없습니다. 다른 미션에 참여해서 포인트를 모아보세요!
All filter: 나중에 다시 올게요
Other filters: 다른 미션 참여하기
Swift
let feedTheme = BZVFeedTheme { builder in
  builder.noFillErrorImage = ...
  builder.noFillErrorTitle = ...
  builder.noFillErrorDescription1st = ...
  builder.noFillErrorDescription2nd = ...
  builder.noFillErrorDescription3rd = ...
  builder.noFillErrorDescriptionFinalAllFilter = ...
  builder.noFillErrorDescriptionFinalOtherFilters = ...
  builder.noFillErrorButton1st = ...
  builder.noFillErrorButton2nd = ...
  builder.noFillErrorButton3rd = ...
  builder.noFillErrorButtonFinalAllFilter = ...
  builder.noFillErrorButtonFinalOtherFilters = ...
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)

User profile error UI

Customize the strings and images shown when no user profile is set.

Swift
let feedTheme = BZVFeedTheme { builder in
  builder.userProfileErrorImage = ...
  builder.userProfileErrorTitle = ...
  builder.userProfileErrorDescription = ...
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)

Other error screens

Customize the image for each error screen.

PropertyDescription
privacyPolicyErrorIconChanges the image shown when third-party sharing consent is required.
agePolicyErrorIconChanges the image shown for a network error.
networkErrorIconChanges the image shown for a network error.
unknownErrorIconChanges the image shown for an unknown error.
Swift
let feedTheme = BZVFeedTheme { builder in
  builder.privacyPolicyErrorImage = ...
  builder.agePolicyErrorImage = ...
  builder.networkErrorImage = ...
  builder.unknownErrorImage = ...
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)

Implement a custom UI for consent to share personal information with third parties

If you implement your own privacy policy UI, you must pass the user's consent status to the SDK. Refer to the table below and call the appropriate function.

ClassAPIDescription
BuzzAdBenefitprivacyPolicyManager (static variable)Returns a BZVPrivacyPolicyManager instance.
BZVPrivacyPolicyManagergrantConsent()Consent to personal information collection.
revokeConsent()Revokes consent to collect personal information.
isConsentGranted()Check whether the user has consented to personal information collection.

Usage example

Swift
let privacyPolicyManager = BuzzAdBenefit.privacyPolicyManager

// 직접 구현한 개인정보 제3자 제공 동의 UI에서 동의를 받았을 경우 아래 코드를 실행하면, 피드 화면에서 개인정보 제3자 제공 동의 UI가 노출되지 않으면서 광고 할당이 정상적으로 진행 됩니다.
// 아래의 코드를 실행하지 않을 경우 피드 진입 시 개인정보 제3자 제공 동의 UI가 노출되기 때문에 필수적으로 실행이 필요합니다.
privacyPolicyManager.grantConsent()

// 아래 코드를 통해서 수집 동의를 철회할 수 있습니다. 이 코드가 실행되면 피드에서 광고 할당이 이루어지지 않습니다.
privacyPolicyManager.revokeConsent()

ATT permission prompt modal

Customize the modal image shown to users on iOS 14 or later who have not allowed app tracking.

Swift
let feedTheme = BZVFeedTheme { builder in
  builder.appTrackingTransparencyGuideModalImage = ...
}
BZVBuzzAdFeed.setDefaultTheme(feedTheme)

Interstitial

Use GlobalTheme to change the primary color, updating the BenefitHub entry prompt, CTA background and reward icon together. See Global theme.