Overview
This document provides practical examples of the Adrop React Native SDK. All examples are written in TypeScript and can be used directly in actual projects.Sample Project
View the complete sample project on GitHub.React Native Sample Project
React Native sample app written in TypeScript
Banner Ad Example
A complete example of manually loading banner ads using refs and handling errors.Copy
import React, { useMemo, useRef, useState } from 'react'
import {
Button,
Dimensions,
Platform,
StyleSheet,
Text,
View,
} from 'react-native'
import { AdropBanner, type AdropBannerMetadata } from 'adrop-ads-react-native'
interface IBanner {
load: () => void
}
const BannerExample: React.FC = () => {
const bannerRef = useRef<IBanner>(null)
const emptyBannerRef = useRef<IBanner>(null)
const [errorCode, setErrorCode] = useState('')
const [emptyErrorCode, setEmptyErrorCode] = useState('')
const unit = useMemo(() => {
// 실제 배너 광고 유닛 ID를 사용하세요
return Platform.OS === 'android'
? 'PUBLIC_TEST_UNIT_ID_320_50'
: 'PUBLIC_TEST_UNIT_ID_320_50'
}, [])
const loadBanner = () => {
bannerRef.current?.load()
setErrorCode('')
}
const loadEmptyBanner = () => {
emptyBannerRef.current?.load()
setEmptyErrorCode('')
}
const onAdClicked = (unitId: string, metadata?: AdropBannerMetadata) =>
console.log('배너 클릭됨', unitId, metadata)
const onAdReceived = (unitId: string, metadata?: AdropBannerMetadata) =>
console.log('배너 수신 성공', unitId, metadata)
const onAdFailedToReceive = (unitId: string, error?: string) => {
console.log('배너 수신 실패', unitId, error)
setErrorCode(error ?? '')
}
const onAdImpression = (unitId: string, metadata?: AdropBannerMetadata) =>
console.log('배너 노출됨', unitId, metadata)
const onEmptyAdFailedToReceive = (_: string, error?: string) => {
console.log('배너 수신 실패', _, error)
setEmptyErrorCode(error ?? '')
}
const screenWidth = Dimensions.get('window').width
return (
<View style={styles.container}>
<Button title={'Load Banner (Test Ad)'} onPress={loadBanner} />
<AdropBanner
ref={bannerRef}
unitId={unit}
style={{ ...styles.banner, width: screenWidth }}
autoLoad={false}
onAdClicked={onAdClicked}
onAdReceived={onAdReceived}
onAdFailedToReceive={onAdFailedToReceive}
onAdImpression={onAdImpression}
/>
{errorCode && (
<Text style={styles.error}>Error Code: {errorCode}</Text>
)}
<View style={styles.divider} />
<Button
title={'Load Banner (Empty Ad)'}
onPress={loadEmptyBanner}
/>
<AdropBanner
ref={emptyBannerRef}
unitId={'TEST_UNIT_ID'}
style={{ ...styles.banner, width: screenWidth }}
autoLoad={false}
onAdFailedToReceive={onEmptyAdFailedToReceive}
/>
{emptyErrorCode && (
<Text style={styles.error}>Error Code: {emptyErrorCode}</Text>
)}
</View>
)
}
export default BannerExample
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
marginVertical: 50,
paddingHorizontal: 16,
},
banner: {
width: '100%',
height: 80,
marginVertical: 4,
},
error: {
marginVertical: 2,
color: 'black',
textAlign: 'center',
},
divider: {
width: '100%',
height: 1,
marginVertical: 16,
backgroundColor: 'black',
},
})
Key Features
- Manual Load: Set
autoLoad={false}and load ads at desired timing via ref - Error Handling: Manage error state with
onAdFailedToReceivecallback - Multiple Banners: Manage multiple banners independently
- Platform Support: Set platform-specific unit IDs using
Platform.OS
Native Ad Example
An example of using native ads with WebView and handling backfill ads.Copy
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import {
AdropBodyView,
AdropHeadLineView,
AdropMediaView,
AdropNativeAd,
AdropNativeAdView,
AdropProfileLogoView,
AdropProfileNameView,
} from 'adrop-ads-react-native'
import { WebView } from 'react-native-webview'
import {
Button,
Dimensions,
ScrollView,
StyleSheet,
Text,
View,
Linking,
Platform,
} from 'react-native'
import type { AdropNativeAdListener } from 'adrop-ads-react-native'
const NativeAdExample: React.FC = () => {
const [nativeAd, setNativeAd] = useState<AdropNativeAd>()
const [isLoaded, setIsLoaded] = useState(false)
const [errorCode, setErrorCode] = useState('')
const disabledReset = !errorCode
const unit = useMemo(() => {
return Platform.OS === 'android'
? 'PUBLIC_TEST_UNIT_ID_NATIVE'
: 'PUBLIC_TEST_UNIT_ID_NATIVE'
}, [])
const openUrl = useCallback((url: string) => {
Linking.openURL(url).catch((err) =>
console.error('URL 열기 실패:', err)
)
}, [])
const listener = useMemo(
(): AdropNativeAdListener => ({
onAdReceived: (ad) => {
console.log(
`네이티브 광고 수신: ${ad.unitId}`,
ad.properties,
ad.txId,
ad.campaignId,
ad.creativeId
)
setIsLoaded(true)
setErrorCode('')
},
onAdFailedToReceive: (_, error) => {
console.log('네이티브 광고 수신 실패', error)
setErrorCode(error)
},
onAdClicked: (ad) => console.log(`네이티브 광고 클릭: ${ad.unitId}`),
onAdImpression: (ad) =>
console.log(`네이티브 광고 노출: ${ad.unitId}`),
}),
[]
)
const initialize = useCallback(
(unitId: string) => {
let adropNativeAd = new AdropNativeAd(unitId)
adropNativeAd.listener = listener
setNativeAd((prev) => {
prev?.destroy()
return adropNativeAd
})
setIsLoaded(false)
setErrorCode('')
},
[listener]
)
useEffect(() => {
initialize(unit)
}, [initialize, unit])
const load = () => nativeAd?.load()
const resetTestAd = () => {
initialize(unit)
}
const resetEmptyAd = () => {
initialize('TEST_UNIT_ID')
}
const adView = useMemo(() => {
if (!isLoaded) return null
return (
<AdropNativeAdView
nativeAd={nativeAd}
style={{
...styles.adContainer,
width: Dimensions.get('window').width,
}}
>
<View style={styles.rowContainer}>
<AdropProfileLogoView style={styles.icon} />
<AdropProfileNameView style={styles.name} />
</View>
<AdropHeadLineView style={styles.headline} />
<AdropBodyView style={styles.body} />
{nativeAd?.isBackfilled ? (
<AdropMediaView style={styles.adStyle} />
) : (
<WebView
source={{
html: nativeAd?.properties?.creative ?? '',
}}
style={styles.adStyle}
javaScriptEnabled={true}
mediaPlaybackRequiresUserAction={false}
allowsInlineMediaPlayback={true}
scrollEnabled={false}
onNavigationStateChange={(event) => {
// Android webview 이벤트
if (
event.url &&
event.url !== 'about:blank' &&
!event.url.startsWith('data:')
) {
openUrl(event.url)
}
}}
onOpenWindow={(event) => {
// iOS webview 이벤트 (window.open)
if (event.nativeEvent?.targetUrl) {
openUrl(event.nativeEvent.targetUrl)
}
}}
/>
)}
</AdropNativeAdView>
)
}, [isLoaded, nativeAd, openUrl])
return (
<ScrollView>
<View style={styles.container}>
<View style={styles.button}>
<Button title={'Load Native Ad'} onPress={load} />
</View>
<View style={styles.button}>
<Button
disabled={disabledReset}
title={'Initialize Native Ad (Test Ad)'}
onPress={resetTestAd}
/>
</View>
{adView}
<Text style={styles.description}>
After initializing the native ad, click the load button to display the ad.
</Text>
<View style={styles.button}>
<Button
disabled={disabledReset}
title={'Initialize Native Ad (Empty Ad)'}
onPress={resetEmptyAd}
/>
</View>
<Text style={styles.description}>
After initializing the native ad, click the load button to trigger the error callback.
</Text>
{errorCode && (
<Text style={styles.error}>Error Code: {errorCode}</Text>
)}
</View>
</ScrollView>
)
}
export default NativeAdExample
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
paddingVertical: 5,
paddingHorizontal: 66,
},
button: {
marginVertical: 4,
},
description: {
color: 'black',
marginBottom: 24,
paddingHorizontal: 16,
textAlign: 'center',
},
error: {
color: 'black',
marginVertical: 2,
},
adContainer: {
paddingHorizontal: 16,
},
adStyle: {
width: '100%',
height: 360,
marginBottom: 24,
},
icon: {
width: 32,
height: 32,
marginRight: 8,
},
name: {
fontSize: 14,
fontWeight: 'bold',
color: 'black',
},
headline: {
fontSize: 16,
fontWeight: 'bold',
color: 'black',
},
body: {
fontSize: 14,
color: 'black',
marginVertical: 16,
},
rowContainer: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
marginBottom: 8,
},
})
Key Features
- Profile Information Display: Show advertiser information using
AdropProfileLogoViewandAdropProfileNameView - WebView Integration: Render HTML creatives with WebView
- Backfill Handling: Handle backfill ads using
isBackfilledproperty - URL Handling: Process WebView navigation events to open external links
- Memory Management: Clean up ad objects with
destroy()method
Interstitial Ad Example
An example of implementing interstitial ads using Hooks.Copy
import React, { useCallback, useMemo, useState } from 'react'
import { Button, Platform, StyleSheet, Text, View } from 'react-native'
import { useAdropInterstitialAd } from 'adrop-ads-react-native'
const InterstitialAdExample: React.FC = () => {
const unit = useMemo(() => {
return Platform.OS === 'android'
? 'PUBLIC_TEST_UNIT_ID_INTERSTITIAL'
: 'PUBLIC_TEST_UNIT_ID_INTERSTITIAL'
}, [])
const [unitId, setUnitId] = useState(unit)
const { load, show, errorCode, reset, isLoaded, isOpened, isReady } =
useAdropInterstitialAd(unitId)
const disabledReset = !(isOpened || errorCode)
const loadAd = useCallback(() => {
if (isReady) {
load()
}
}, [isReady, load])
const resetTestAd = useCallback(() => {
reset()
setUnitId(unit)
}, [reset, unit])
const resetEmptyAd = useCallback(() => {
reset()
setUnitId('TEST_UNIT_ID')
}, [reset])
return (
<View style={styles.container}>
<View style={styles.button}>
<Button title={'Load Interstitial Ad'} onPress={loadAd} />
</View>
<View style={styles.button}>
<Button
disabled={!isLoaded}
title={'Show Interstitial Ad'}
onPress={show}
/>
</View>
<View style={styles.button}>
<Button
disabled={disabledReset}
title={'Initialize Interstitial Ad (Test Ad)'}
onPress={resetTestAd}
/>
</View>
<Text style={styles.description}>
After initializing the interstitial ad, click the load button to load the ad.
</Text>
<View style={styles.button}>
<Button
disabled={disabledReset}
title={'Initialize Interstitial Ad (Empty Ad)'}
onPress={resetEmptyAd}
/>
</View>
<Text style={styles.description}>
After initializing the interstitial ad, click the load button to trigger the error callback.
</Text>
{errorCode && (
<Text style={styles.error}>Error Code: {errorCode}</Text>
)}
</View>
)
}
export default InterstitialAdExample
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
marginVertical: 50,
},
button: {
marginVertical: 4,
},
description: {
color: 'black',
marginBottom: 24,
paddingHorizontal: 16,
textAlign: 'center',
},
error: {
color: 'black',
marginVertical: 2,
},
})
Key Features
- Hook Usage: Easy state management with
useAdropInterstitialAdHook - State Tracking: Track ad state using
isLoaded,isOpened,isReadystates - Error Handling: Check error state with
errorCode - Initialization: Initialize ads with
reset()method
Since interstitial ads cover the entire screen, it’s important to display them at appropriate times considering user experience.
Rewarded Ad Example
An example of implementing rewarded ads using Hooks.Copy
import React, { useCallback, useMemo, useState } from 'react'
import { Button, Platform, StyleSheet, Text, View } from 'react-native'
import { useAdropRewardedAd } from 'adrop-ads-react-native'
const RewardedAdExample: React.FC = () => {
const unit = useMemo(() => {
return Platform.OS === 'android'
? 'PUBLIC_TEST_UNIT_ID_REWARDED'
: 'PUBLIC_TEST_UNIT_ID_REWARDED'
}, [])
const [unitId, setUnitId] = useState(unit)
const { load, show, errorCode, reset, isLoaded, isOpened, isReady } =
useAdropRewardedAd(unitId)
const disabledReset = !(isOpened || errorCode)
const loadAd = useCallback(() => {
if (isReady) {
load()
}
}, [isReady, load])
const resetTestAd = useCallback(() => {
reset()
setUnitId(unit)
}, [reset, unit])
const resetEmptyAd = useCallback(() => {
reset()
setUnitId('TEST_UNIT_ID')
}, [reset])
return (
<View style={styles.container}>
<View style={styles.button}>
<Button title={'Load Rewarded Ad'} onPress={loadAd} />
</View>
<View style={styles.button}>
<Button
disabled={!isLoaded}
title={'Show Rewarded Ad'}
onPress={show}
/>
</View>
<View style={styles.button}>
<Button
disabled={disabledReset}
title={'Initialize Rewarded Ad (Test Ad)'}
onPress={resetTestAd}
/>
</View>
<Text style={styles.description}>
After initializing the rewarded ad, click the load button to load the ad.
</Text>
<View style={styles.button}>
<Button
disabled={disabledReset}
title={'Initialize Rewarded Ad (Empty Ad)'}
onPress={resetEmptyAd}
/>
</View>
<Text style={styles.description}>
After initializing the rewarded ad, click the load button to trigger the error callback.
</Text>
{errorCode && (
<Text style={styles.error}>Error Code: {errorCode}</Text>
)}
</View>
)
}
export default RewardedAdExample
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
marginVertical: 50,
},
button: {
marginVertical: 4,
},
description: {
color: 'black',
marginBottom: 24,
paddingHorizontal: 16,
textAlign: 'center',
},
error: {
color: 'black',
marginVertical: 2,
},
})
Key Features
- Hook Usage: Easy state management with
useAdropRewardedAdHook - Reward Handling: Check reward timing via listener (see Rewarded Ad Guide for listener setup)
- State Management: Check ad state with
isLoaded,isOpened,isReady
Rewarded ads require users to watch the entire ad to receive rewards. Only grant rewards in the
onEarnReward callback.Popup Ad Example
An example of implementing and customizing popup ads using classes.Copy
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { Button, Platform, StyleSheet, Text, View } from 'react-native'
import {
type AdropListener,
AdropPopupAd,
type AdropPopupAdColors,
} from 'adrop-ads-react-native'
const PopupAdExample: React.FC = () => {
const [popupAd, setPopupAd] = useState<AdropPopupAd>()
const [isLoaded, setIsLoaded] = useState(false)
const [isShown, setIsShown] = useState(false)
const [errorCode, setErrorCode] = useState('')
const disabledReset = !(errorCode || isShown)
const unit = useMemo(() => {
return Platform.OS === 'android'
? 'PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM'
: 'PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM'
}, [])
const listener: AdropListener = useMemo(() => {
return {
onAdImpression: (ad: AdropPopupAd) =>
console.log(
`팝업 광고 노출: ${ad.unitId}, ${ad.createIds()}, ${
ad.txId
}, ${ad.campaignId} ${ad.destinationURL}`
),
onAdClicked: (ad: AdropPopupAd) => {
console.log(
`팝업 광고 클릭: ${ad.unitId}, ${ad.destinationURL}`
)
ad.close()
},
onAdReceived: (ad: AdropPopupAd) => {
setIsLoaded(true)
console.log(`팝업 광고 수신: ${ad.unitId}`)
setErrorCode('')
},
onAdFailedToReceive: (_: AdropPopupAd, error: any) => {
console.log('팝업 광고 수신 실패', error)
setErrorCode(error)
},
onAdDidDismissFullScreen: (ad: AdropPopupAd) =>
console.log(`팝업 광고 닫힘: ${ad.unitId}`),
onAdDidPresentFullScreen: (ad: AdropPopupAd) =>
console.log(`팝업 광고 표시됨: ${ad.unitId}`),
onAdFailedToShowFullScreen: (_: AdropPopupAd, error: any) =>
setErrorCode(error),
} as AdropListener
}, [])
useEffect(() => {
return () => {
popupAd?.destroy()
}
}, [popupAd])
const initialize = useCallback(
(unitId: string) => {
// 팝업 광고 색상 커스터마이징
let hideForTodayTextColor = '#456'
let backgroundColor = 'rgba(53, 255, 63, 0.3)'
let customColors: AdropPopupAdColors = {
hideForTodayTextColor,
backgroundColor,
}
let adropPopupAd = new AdropPopupAd(unitId, customColors)
adropPopupAd.listener = listener
setPopupAd((prev) => {
prev?.destroy()
return adropPopupAd
})
},
[listener]
)
useEffect(() => {
initialize(unit)
}, [initialize, unit])
const load = () => popupAd?.load()
const show = () => {
popupAd?.show()
setIsShown(true)
}
const resetTestAd = () => {
initialize(unit)
resetState()
}
const resetEmptyAd = () => {
initialize('TEST_UNIT_ID')
resetState()
}
const resetState = () => {
setIsLoaded(false)
setIsShown(false)
setErrorCode('')
}
return (
<View style={styles.container}>
<View style={styles.button}>
<Button title={'Load Popup Ad'} onPress={load} />
</View>
<View style={styles.button}>
<Button
disabled={!isLoaded}
title={'Show Popup Ad'}
onPress={show}
/>
</View>
<View style={styles.button}>
<Button
disabled={disabledReset}
title={'Initialize Popup Ad (Test Ad)'}
onPress={resetTestAd}
/>
</View>
<Text style={styles.description}>
After initializing the popup ad, click the load button to load the ad.
</Text>
<View style={styles.button}>
<Button
disabled={disabledReset}
title={'Initialize Popup Ad (Empty Ad)'}
onPress={resetEmptyAd}
/>
</View>
<Text style={styles.description}>
After initializing the popup ad, click the load button to trigger the error callback.
</Text>
{errorCode && (
<Text style={styles.error}>Error Code: {errorCode}</Text>
)}
</View>
)
}
export default PopupAdExample
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
marginVertical: 50,
},
button: {
marginVertical: 4,
},
description: {
color: 'black',
marginBottom: 24,
paddingHorizontal: 16,
textAlign: 'center',
},
error: {
color: 'black',
marginVertical: 2,
},
})
Key Features
- Class-based: Direct use of
AdropPopupAdclass - Color Customization: Set popup style with
AdropPopupAdColors - Close on Click: Call
ad.close()inonAdClicked - Memory Management: Call
destroy()inuseEffectcleanup
Targeting Configuration Example
An example of setting ad targeting.Copy
import React, { useEffect } from 'react'
import { View } from 'react-native'
import Adrop, { AdropGender } from 'adrop-ads-react-native'
const TargetingExample: React.FC = () => {
useEffect(() => {
// 사용자 성별 설정
Adrop.setProperty('gender', AdropGender.MALE)
// 사용자 나이 설정
Adrop.setProperty('age', 25)
// 사용자 생년월일 설정
Adrop.setProperty('birth', '1998-05-20')
// 커스텀 속성 설정 (문자열)
Adrop.setProperty('customKey', 'customValue')
// 커스텀 속성 설정 (숫자)
Adrop.setProperty('level', 10)
// 커스텀 속성 설정 (불린)
Adrop.setProperty('isPremium', true)
}, [])
return <View />
}
export default TargetingExample
Available Targeting Properties
| Property | Type | Description |
|---|---|---|
gender | AdropGender | User gender (MALE, FEMALE, UNKNOWN) |
age | number | User age |
birth | string | User date of birth (YYYY-MM-DD) |
| Custom key | string | number | boolean | Custom properties defined by the app |
Targeting properties are sent to the server during ad requests to display more relevant ads.
Error Handling Utility
A utility example that converts error codes into human-readable messages.Copy
import { AdropErrorCode } from 'adrop-ads-react-native'
export const descriptionOf = (errorCode: string): string => {
switch (errorCode) {
case AdropErrorCode.network:
return 'Network connection is unstable'
case AdropErrorCode.internal:
return 'An SDK internal error occurred'
case AdropErrorCode.initialize:
return 'Adrop must be initialized first'
case AdropErrorCode.invalidUnit:
return 'Ad unit ID is invalid'
case AdropErrorCode.notTargetCountry:
return 'SDK cannot be used in unsupported countries'
case AdropErrorCode.inactive:
return 'No active ad campaigns available'
case AdropErrorCode.adNoFill:
return 'No ads matching the criteria. Please try again'
case AdropErrorCode.adDuplicated:
return 'Cannot reload after ad has been received'
case AdropErrorCode.adLoading:
return 'Waiting for server response after ad request'
case AdropErrorCode.adEmpty:
return 'No ad received'
case AdropErrorCode.adShown:
return 'This ad has already been shown'
case AdropErrorCode.adHideForToday:
return 'Cannot load more today'
case AdropErrorCode.adLandscapeUnsupported:
return 'Ads cannot be displayed in landscape mode'
case AdropErrorCode.undefined:
return 'Undefined error'
default:
return ''
}
}
Error Code List
| Error Code | Description |
|---|---|
network | Network connection issue |
internal | SDK internal error |
initialize | SDK initialization required |
invalidUnit | Invalid unit ID |
notTargetCountry | Unsupported country |
inactive | No active campaigns |
adNoFill | No ads available |
adDuplicated | Duplicate load attempt |
adLoading | Ad loading in progress |
adEmpty | Ad not received |
adShown | Ad already shown |
adHideForToday | ”Don’t show today” selected |
adLandscapeUnsupported | Landscape mode not supported |
Full Integration Example
An example of using all ad formats in a single app.Copy
import React, { useEffect } from 'react'
import { NavigationContainer } from '@react-navigation/native'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import Adrop from 'adrop-ads-react-native'
import BannerExample from './views/BannerExample'
import NativeAdExample from './views/NativeAdExample'
import InterstitialAdExample from './views/InterstitialAdExample'
import RewardedAdExample from './views/RewardedAdExample'
import PopupAdExample from './views/PopupAdExample'
const Tab = createBottomTabNavigator()
const App = () => {
useEffect(() => {
// Adrop SDK 초기화
Adrop.initialize(false) // 테스트 모드: false, 프로덕션: true
}, [])
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen
name="Banner"
component={BannerExample}
/>
<Tab.Screen
name="Native"
component={NativeAdExample}
/>
<Tab.Screen
name="Interstitial"
component={InterstitialAdExample}
/>
<Tab.Screen
name="Rewarded"
component={RewardedAdExample}
/>
<Tab.Screen
name="Popup"
component={PopupAdExample}
/>
</Tab.Navigator>
</NavigationContainer>
)
}
export default App
Best Practices
1. Memory Management
Always clean up ad objects after use.Copy
useEffect(() => {
const nativeAd = new AdropNativeAd('YOUR_UNIT_ID')
return () => {
nativeAd.destroy()
}
}, [])
2. Error Handling
Implement error handling for all ad loads.Copy
const [error, setError] = useState<string | null>(null)
const handleAdFailedToReceive = (unitId: string, errorCode?: string) => {
setError(errorCode ?? 'Unknown error')
// Error logging, display fallback content, etc.
}
3. State Management
Track ad state using Hooks.Copy
const { isLoaded, isOpened, isReady, errorCode } = useAdropInterstitialAd(unitId)
// Disable button
<Button
disabled={!isLoaded}
title="Show Ad"
onPress={show}
/>
4. Platform Branching
Use different unit IDs for each platform.Copy
const unitId = useMemo(() => {
return Platform.OS === 'android'
? 'ANDROID_UNIT_ID'
: 'IOS_UNIT_ID'
}, [])
5. Use Test Unit IDs
Always use test unit IDs during development and testing.Copy
const isProduction = false
const unitId = isProduction
? 'YOUR_PRODUCTION_UNIT_ID'
: 'PUBLIC_TEST_UNIT_ID_320_50'