배너 배치 관리하기
고유 속성에 액세스하고 노출 횟수를 기록하는 등 Braze SDK에서 배너 배치를 생성하고 관리하는 방법을 알아보세요. 자세한 내용은 배너 정보를 참조하세요.
배치 요청 정보
앱이나 웹사이트에서 배치를 [생성할 때<1>, 앱은 Braze에 배치별 배너 메시지를 가져오도록 요청합니다.
- 새로 고침 요청당 최대 10개의 배치를 요청할 수 있습니다.
- 각 배치에 대해 Braze는 사용자가 받을 수 있는 가장 높은 우선 순위의 배너를 반환합니다.
- 새로 고침에서 10개 이상의 배치가 요청되면 처음 10개만 반환되고 나머지는 버려집니다.
예를 들어, 앱은 새로 고침 요청에서 세 개의 배치: homepage_promo, cart_abandonment, 및 seasonal_offer을 요청할 수 있습니다. 각 요청은 해당 배치에 대한 가장 관련성 높은 배너를 반환합니다.
새로 고침 요청에 대한 비율 제한
구형 SDK 버전(스위프트 13.1.0 이전, 안드로이드 38.0.0, 웹 6.1.0, 리액트 네이티브 17.0.0, 플러터 15.0.0)을 사용하는 경우, 사용자 세션당 하나의 새로 고침 요청만 허용됩니다.
최신 최소 SDK 버전(스위프트 13.1.0+, 안드로이드 38.0.0+, 웹 6.1.0+, 리액트 네이티브 17.0.0+, 플러터 15.0.0+)을 사용하는 경우, 새로 고침 요청은 과도한 폴링을 방지하기 위해 토큰 버킷 알고리즘에 의해 제어됩니다:
- 각 사용자 세션은 다섯 개의 새로 고침 토큰으로 시작합니다.
- 토큰은 180초(3분)마다 하나의 토큰 비율로 보충됩니다.
requestBannersRefresh에 대한 각 호출은 하나의 토큰을 소모합니다. 토큰이 없을 때 새로 고침을 시도하면 SDK는 요청을 하지 않고 토큰이 보충될 때까지 오류를 기록합니다. 이는 중간 세션 및 이벤트 트리거 업데이트에 중요합니다. 동적 업데이트를 구현하려면(예: 사용자가 동일한 페이지에서 작업을 완료한 후), 사용자 정의 이벤트가 기록된 후 새로 고침 메서드를 호출하되, 사용자가 다른 배너 캠페인에 적격이 되기 전에 Braze가 이벤트를 수집하고 처리하는 데 필요한 지연을 고려해야 합니다.
배치 생성
필수 조건
배너 배치를 만드는 데 필요한 최소 소프트웨어 개발 키트 버전입니다:
1단계: Braze에서 플레이스 만들기
아직 만들지 않았다면 앱이나 사이트에서 배너를 표시할 수 있는 위치를 정의하는 데 사용되는 배너 배치를 Braze에서 만들어야 합니다. 게재 위치를 만들려면 설정 > 배너 게재 위치로 이동한 다음 게재 위치 만들기를 선택합니다.

배치에 이름을 지정하고 배치 ID를 할당합니다. ID는 카드의 수명 주기 동안 사용되며 나중에 변경해서는 안 되므로 할당하기 전에 다른 팀과 상의하세요. 자세한 내용은 배치 ID.

2단계: 앱의 게재 위치 새로 고침
아래에 설명된 새로고침 메서드를 호출하여 게재 위치를 새로고침할 수 있습니다. 이러한 게재 위치는 사용자 세션이 만료되거나 changeUser 메서드를 사용하여 식별자를 변경할 때 자동으로 캐시됩니다.
배너 다운로드 또는 표시가 지연되지 않도록 가능한 한 빨리 게재 위치를 새로고침하세요.
1
2
3
import * as braze from "@braze/web-sdk";
braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]);
1
AppDelegate.braze?.banners.requestRefresh(placementIds: ["global_banner", "navigation_square_banner"])
1
2
3
4
ArrayList<String> listOfBanners = new ArrayList<>();
listOfBanners.add("global_banner");
listOfBanners.add("navigation_square_banner");
Braze.getInstance(context).requestBannersRefresh(listOfBanners);
1
Braze.getInstance(context).requestBannersRefresh(listOf("global_banner", "navigation_square_banner"))
1
Braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]);
1
This feature is not currently supported on Unity.
1
This feature is not currently supported on Cordova.
1
braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]);
1
This feature is not currently supported on Roku.
3단계: 업데이트 듣기
이 가이드의 소프트웨어 개발 키트 방법을 사용하여 배너를 삽입하면 모든 분석 이벤트(노출 횟수 및 클릭 수 등)가 자동으로 처리되며, 배너가 표시될 때만 노출 횟수가 기록됩니다.
Web Braze 소프트웨어 개발 키트와 함께 바닐라 JavaScript를 사용하는 경우 subscribeToBannersUpdates 를 사용하여 게재 위치 업데이트를 수신한 다음 requestBannersRefresh 를 호출하여 가져옵니다.
1
2
3
4
5
6
7
8
import * as braze from "@braze/web-sdk";
braze.subscribeToBannersUpdates((banners) => {
console.log("Banners were updated");
});
// always refresh after your subscriber function has been registered
braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]);
Web Braze 소프트웨어 개발 키트와 함께 React를 사용하는 경우, 설정하세요. subscribeToBannersUpdates 를 useEffect 훅 안에 설정하고 requestBannersRefresh 를 호출하세요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import * as braze from "@braze/web-sdk";
useEffect(() => {
const subscriptionId = braze.subscribeToBannersUpdates((banners) => {
console.log("Banners were updated");
});
// always refresh after your subscriber function has been registered
braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]);
// cleanup listeners
return () => {
braze.removeSubscription(subscriptionId);
}
}, []);
1
2
3
4
5
let cancellable = brazeClient.braze()?.banners.subscribeToUpdates { banners in
banners.forEach { placementId, banner in
print("Received banner: \(banner) with placement ID: \(placementId)")
}
}
1
2
3
4
5
Braze.getInstance(context).subscribeToBannersUpdates(banners -> {
for (Banner banner : banners.getBanners()) {
Log.d(TAG, "Received banner: " + banner.getPlacementId());
}
});
1
2
3
4
5
Braze.getInstance(context).subscribeToBannersUpdates { update ->
for (banner in update.banners) {
Log.d(TAG, "Received banner: " + banner.placementId)
}
}
1
2
3
4
5
6
7
8
9
10
const bannerCardsSubscription = Braze.addListener(
Braze.Events.BANNER_CARDS_UPDATED,
(data) => {
const banners = data.banners;
console.log(
`Received ${banners.length} Banner Cards with placement IDs:`,
banners.map((banner) => banner.placementId)
);
}
);
1
This feature is not currently supported on Unity.
1
This feature is not currently supported on Cordova.
1
2
3
4
5
StreamSubscription bannerStreamSubscription = braze.subscribeToBanners((List<BrazeBanner> banners) {
for (final banner in banners) {
print("Received banner: " + banner.toString());
}
});
1
This feature is not currently supported on Roku.
4단계: 배치 ID를 사용하여 삽입
전체 단계별 튜토리얼을 보려면 배치 ID로 배너 표시하기를 확인하세요.
배너의 컨테이너 요소를 만듭니다. 너비와 높이를 설정해야 합니다.
1
<div id="global-banner-container" style="width: 100%; height: 450px;"></div>
Web Braze 소프트웨어 개발 키트와 함께 바닐라 JavaScript를 사용하는 경우 insertBanner 메서드를 호출하여 컨테이너 요소의 내부 HTML을 교체하세요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import * as braze from "@braze/web-sdk";
braze.initialize("sdk-api-key", {
baseUrl: "sdk-base-url",
allowUserSuppliedJavascript: true, // banners require you to opt-in to user-supplied javascript
});
braze.subscribeToBannersUpdates((banners) => {
// get this placement's banner. If it's `null` the user did not qualify for one.
const globalBanner = braze.getBanner("global_banner");
if (!globalBanner) {
return;
}
// choose where in the DOM you want to insert the banner HTML
const container = document.getElementById("global-banner-container");
// Insert the banner which replaces the innerHTML of that container
braze.insertBanner(globalBanner, container);
// Special handling if the user is part of a Control Variant
if (globalBanner.isControl) {
// hide or collapse the container
container.style.display = "none";
}
});
braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]);
Web Braze 소프트웨어 개발 키트와 함께 React를 사용하는 경우, 컨테이너 엘리먼트의 내부 HTML을 바꾸려면 insertBanner 메서드를 ref 로 호출하여 컨테이너 엘리먼트의 내부 HTML을 대체하세요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { useRef } from 'react';
import * as braze from "@braze/web-sdk";
export default function App() {
const bannerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const globalBanner = braze.getBanner("global_banner");
if (!globalBanner || globalBanner.isControl) {
// hide the container
} else {
// insert the banner to the container node
braze.insertBanner(globalBanner, bannerRef.current);
}
}, []);
return <div ref={bannerRef}></div>
}
노출 수를 추적하려면 insertBanner 으로 전화하여 isControl. 그런 다음 나중에 컨테이너를 숨기거나 접을 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// To get access to the Banner model object:
let globalBanner: Braze.Banner?
AppDelegate.braze?.banners.getBanner(for: "global_banner", { banner in
self.globalBanner = banner
})
// If you simply want the Banner view, you may initialize a `UIView` with the placement ID:
if let braze = AppDelegate.braze {
let bannerUIView = BrazeBannerUI.BannerUIView(
placementId: "global_banner",
braze: braze,
// iOS does not perform automatic resizing or visibility changes.
// Use the `processContentUpdates` parameter to adjust the size and visibility of your Banner according to your use case.
processContentUpdates: { result in
switch result {
case .success(let updates):
if let height = updates.height {
// Adjust the visibility and/or height.
}
case .failure(let error):
// Handle the error.
}
}
)
}
// Similarly, if you want a Banner view in SwiftUI, use the corresponding `BannerView` initializer:
if let braze = AppDelegate.braze {
let bannerView = BrazeBannerUI.BannerView(
placementId: "global_banner",
braze: braze,
// iOS does not perform automatic resizing or visibility changes.
// Use the `processContentUpdates` parameter to adjust the size and visibility of your Banner according to your use case.
processContentUpdates: { result in
switch result {
case .success(let updates):
if let height = updates.height {
// Adjust the visibility and/or height according to your parent controller.
}
case .failure(let error):
// Handle the error.
}
}
)
}
Java 코드로 배너를 가져오려면 다음을 사용합니다:
1
Banner globalBanner = Braze.getInstance(context).getBanner("global_banner");
이 XML을 포함하여 Android 보기 레이아웃에 배너를 만들 수 있습니다:
1
2
3
4
5
<com.braze.ui.banners.BannerView
android:id="@+id/global_banner_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:placementId="global_banner" />
Android 보기를 사용하는 경우 이 XML을 사용하세요:
1
2
3
4
5
<com.braze.ui.banners.BannerView
android:id="@+id/global_banner_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:placementId="global_banner" />
젯팩 컴포즈를 사용하는 경우 이 기능을 사용할 수 있습니다:
1
Banner(placementId = "global_banner")
Kotlin에서 배너를 가져오려면 다음을 사용하세요:
1
val banner = Braze.getInstance(context).getBanner("global_banner")
React Native의 새 아키텍처를 사용하는 경우, AppDelegate.mm 에 BrazeBannerView 을 패브릭 컴포넌트로 등록해야 합니다.
1
2
3
4
5
6
7
8
#ifdef RCT_NEW_ARCH_ENABLED
/// Register the `BrazeBannerView` for use as a Fabric component.
- (NSDictionary<NSString *,Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents {
NSMutableDictionary * dictionary = [super thirdPartyFabricComponents].mutableCopy;
dictionary[@"BrazeBannerView"] = [BrazeBannerView class];
return dictionary;
}
#endif
가장 간단한 통합을 위해 배치 ID만 제공하는 다음 JSX(JavaScript XML) 스니펫을 뷰 계층 구조에 추가합니다.
1
2
3
<Braze.BrazeBannerView
placementID='global_banner'
/>
리액트 네이티브에서 배너의 데이터 모델을 가져오거나 사용자 캐시에 해당 배치가 있는지 확인하려면 다음을 사용하세요:
1
const banner = await Braze.getBanner("global_banner");
1
This feature is not currently supported on Unity.
1
This feature is not currently supported on Cordova.
가장 간단한 통합을 위해 다음 위젯을 뷰 계층 구조에 추가하고 배치 ID만 제공하면 됩니다.
1
2
3
4
BrazeBannerView(
placementId: "global_banner",
),
To get the Banner's data model in Flutter, use:
getBanner 메서드를 사용하여 사용자 캐시에 해당 배치가 있는지 확인할 수 있습니다.
1
2
3
4
5
6
7
braze.getBanner("global_banner").then((banner) {
if (banner == null) {
// Handle null cases.
} else {
print(banner.toString());
}
});
1
This feature is not currently supported on Roku.
5단계: 테스트 배너 보내기(선택 사항)
배너 캠페인을 시작하기 전에 테스트 배너를 전송하여 연동 여부를 확인할 수 있습니다. 테스트 배너는 별도의 인메모리 캐시에 저장되며 앱 재시작 시에도 유지되지 않습니다. 추가 설정은 필요하지 않지만, 테스트 기기가 테스트를 표시할 수 있도록 전경 푸시 알림을 수신할 수 있어야 합니다.
테스트 배너는 다음 앱 세션에서 제거된다는 점을 제외하면 다른 배너와 비슷합니다.
로그 노출 횟수
소프트웨어 개발 키트 방식을 사용하여 배너를 삽입할 때 노출되는 배너의 노출 횟수를 Braze가 자동으로 기록하므로 수동으로 노출 횟수를 추적할 필요가 없습니다.
클릭 수 로깅
배너 클릭을 기록하는 데 사용되는 방법은 배너가 렌더링되는 방식과 클릭 핸들러의 위치에 따라 달라집니다.
표준 배너 콘텐츠(자동)
기본값으로 제공되는 소프트웨어 개발 키트 방법을 사용하여 배너를 삽입하고 배너에 표준 편집기 구성요소(이미지, 버튼, 텍스트)를 사용하는 경우 클릭이 자동으로 추적됩니다. 소프트웨어 개발 키트는 이러한 요소에 클릭 리스너를 연결하므로 추가 코드가 필요하지 않습니다.
커스텀 코드 블록
배너가 Braze 대시보드의 커스텀 코드 편집기 블록을 사용하는 경우 brazeBridge.logClick() 을 사용하여 해당 커스텀 HTML 내에서 클릭을 기록해야 합니다. 이는 소프트웨어 개발 키트에서 커스텀 코드 내부의 요소에 리스너를 자동으로 첨부할 수 없으므로 SDK 메서드를 사용하여 배너를 렌더링하는 경우에도 적용됩니다.
1
2
3
<button onclick="brazeBridge.logClick()">
Click me
</button>
이는 HTML 인앱 메시징에 사용되는 자바스크립트 브릿지와 유사합니다. brazeBridge 은 배너의 내부 HTML과 상위 Braze 소프트웨어 개발 키트 간의 통신 계층을 제공합니다.
커스텀 UI 구현(헤드리스)
배너 HTML을 렌더링하지 않고 배너의 커스텀 속성을 사용하여 완전한 커스텀 UI를 구축하는 경우 애플리케이션 코드에서 클릭 수(및 노출 횟수)를 수동으로 기록해야 합니다. 소프트웨어 개발 키트에서는 배너를 렌더링하지 않기 때문에 커스텀 UI 요소와의 상호작용을 자동으로 추적할 수 있는 방법이 없습니다.
배너 객체에서 logClick() 메서드를 사용합니다.
크기 및 크기 조정
배너 크기 및 크기 조정에 대해 알아야 할 사항은 다음과 같습니다:
- 컴포저를 사용하면 배너를 다양한 크기로 미리 볼 수 있지만, 해당 정보는 SDK에 저장되거나 전송되지 않습니다.
- HTML은 렌더링되는 컨테이너의 전체 너비를 차지합니다.
- 고정된 치수 요소를 만들고 컴포저에서 해당 치수를 테스트하는 것이 좋습니다.
커스텀 속성
배너 캠페인의 커스텀 속성을 사용하여 소프트웨어 개발 키트를 통해 키값 데이터를 검색하고 앱의 행동이나 모양을 수정할 수 있습니다. 예를 들어, 다음과 같이 할 수 있습니다:
- 타사 분석 또는 통합을 위한 메타데이터를 전송하세요.
timestamp또는 JSON 객체와 같은 메타데이터를 사용하여 조건 로직을 트리거하세요.ratio또는format과 같이 포함된 메타데이터를 기반으로 배너의 동작을 제어합니다.
필수 조건
배너 캠페인에 커스텀 속성을 추가해야 합니다. 또한 커스텀 속성에 액세스하는 데 필요한 최소 소프트웨어 개발 키트 버전입니다:
커스텀 속성에 액세스하기
배너의 커스텀 속성에 액세스하려면 대시보드에 정의된 속성 유형에 따라 다음 방법 중 하나를 사용합니다. 키가 해당 유형의 속성과 일치하지 않거나 존재하지 않으면 메서드는 null 을 반환합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Returns the Banner instance
const banner = braze.getBanner("placement_id_homepage_top");
// banner may be undefined or null
if (banner) {
// Returns the string property
const stringProperty = banner.getStringProperty("color");
// Returns the boolean property
const booleanProperty = banner.getBooleanProperty("expanded");
// Returns the number property
const numberProperty = banner.getNumberProperty("height");
// Returns the timestamp property (as a number)
const timestampProperty = banner.getTimestampProperty("account_start");
// Returns the image URL property as a string of the URL
const imageProperty = banner.getImageProperty("homepage_icon");
// Returns the JSON object property
const jsonObjectProperty = banner.getJsonProperty("footer_settings");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Passes the specified banner to the completion handler
AppDelegate.braze?.banners.getBanner(for: "placement_id_homepage_top") { banner in
// Returns the string property
let stringProperty: String? = banner.stringProperty(key: "color")
// Returns the boolean property
let booleanProperty: Bool? = banner.boolProperty(key: "expanded")
// Returns the number property as a double
let numberProperty: Double? = banner.numberProperty(key: "height")
// Returns the Unix UTC millisecond timestamp property as an integer
let timestampProperty: Int? = banner.timestampProperty(key: "account_start")
// Returns the image property as a String of the image URL
let imageProperty: String? = banner.imageProperty(key: "homepage_icon")
// Returns the JSON object property as a [String: Any] dictionary
let jsonObjectProperty: [String: Any]? = banner.jsonObjectProperty(key: "footer_settings")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Returns the Banner instance
Banner banner = Braze.getInstance(context).getBanner("placement_id_homepage_top");
// banner may be undefined or null
if (banner != null) {
// Returns the string property
String stringProperty = banner.getStringProperty("color");
// Returns the boolean property
Boolean booleanProperty = banner.getBooleanProperty("expanded");
// Returns the number property
Number numberProperty = banner.getNumberProperty("height");
// Returns the timestamp property (as a Long)
Long timestampProperty = banner.getTimestampProperty("account_start");
// Returns the image URL property as a String of the URL
String imageProperty = banner.getImageProperty("homepage_icon");
// Returns the JSON object property as a JSONObject
JSONObject jsonObjectProperty = banner.getJSONProperty("footer_settings");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Returns the Banner instance
val banner: Banner = Braze.getInstance(context).getBanner("placement_id_homepage_top") ?: return
// Returns the string property
val stringProperty: String? = banner.getStringProperty("color")
// Returns the boolean property
val booleanProperty: Boolean? = banner.getBooleanProperty("expanded")
// Returns the number property
val numberProperty: Number? = banner.getNumberProperty("height")
// Returns the timestamp property (as a Long)
val timestampProperty: Long? = banner.getTimestampProperty("account_start")
// Returns the image URL property as a String of the URL
val imageProperty: String? = banner.getImageProperty("homepage_icon")
// Returns the JSON object property as a JSONObject
val jsonObjectProperty: JSONObject? = banner.getJSONProperty("footer_settings")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Get the Banner instance
const banner = await Braze.getBanner('placement_id_homepage_top');
if (!banner) return;
// Get the string property
const stringProperty = banner.getStringProperty('color');
// Get the boolean property
const booleanProperty = banner.getBooleanProperty('expanded');
// Get the number property
const numberProperty = banner.getNumberProperty('height');
// Get the timestamp property (as a number)
const timestampProperty = banner.getTimestampProperty('account_start');
// Get the image URL property as a string
const imageProperty = banner.getImageProperty('homepage_icon');
// Get the JSON object property
const jsonObjectProperty = banner.getJSONProperty('footer_settings');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Fetch the banner asynchronously
_braze.getBanner(placementId).then(('placement_id_homepage_top') {
// Get the string property
final String? stringProperty = banner?.getStringProperty('color');
// Get the boolean property
final bool? booleanProperty = banner?.getBooleanProperty('expanded');
// Get the number property
final num? numberProperty = banner?.getNumberProperty('height');
// Get the timestamp property
final int? timestampProperty = banner?.getTimestampProperty('account_start');
// Get the image URL property
final String? imageProperty = banner?.getImageProperty('homepage_icon');
// Get the JSON object propertyßß
final Map<String, dynamic>? jsonObjectProperty = banner?.getJSONProperty('footer_settings');
// Use these properties as needed in your UI or logic
});
GitHub 에서 이 페이지를 편집합니다.