capacitor-levelplay
v0.3.0
Published
Capacitor 7 and 8 plugin for Unity LevelPlay (ironSource) ads on Android and iOS: rewarded, interstitial, banner and native ads, impression-level revenue, segments, ad-unit API, Swift Package Manager first, ATT and GDPR / CCPA / COPPA consent.
Maintainers
Readme
capacitor-levelplay
Capacitor 7 and 8 plugin for Unity LevelPlay (formerly ironSource)
mediation: rewarded, interstitial, banner and native ads on Android and iOS, plus impression-level
revenue data, built on LevelPlay's current ad-unit API (LevelPlay.init, LevelPlayRewardedAd / LPMRewardedAd,
LevelPlayInterstitialAd / LPMInterstitialAd, LevelPlayBannerAdView / LPMBannerAdView, LevelPlayNativeAd).
import { LevelPlay } from 'capacitor-levelplay';
await LevelPlay.initialize({ appKey: 'your-app-key' });
await LevelPlay.loadRewarded({ adUnitId: 'your-rewarded-ad-unit' });
// ...
const result = await LevelPlay.showRewarded({ adUnitId: 'your-rewarded-ad-unit' });
if (result.rewarded) grantCoins(result.reward!.amount);Contents
- Features
- Compatibility
- Install
- iOS setup
- Android setup
- Quick start
- Usage guide
- Example app
- Mediation adapters
- Privacy and consent
- Limitations
- Troubleshooting
- FAQ
- API reference
- Contributing
- License
Features
- Rewarded and interstitial ads with LevelPlay's ad-unit API (SDK 9.x). One native ad object per ad unit id, so several rewarded or interstitial ad units can be used side by side.
- Promise-based show:
showRewarded/showInterstitialresolve after the ad closes with{ shown, rewarded, reward?, error?, adInfo? }. They never reject because an ad was not ready, and the plugin handles networks that deliver the reward after the close callback. - Swift Package Manager first on iOS: the plugin's
Package.swiftdepends on Unity's official LevelPlay-Swift-Package, sonpx cap syncon an SPM project really pulls the SDK. A podspec (IronSourceSDK) is included for CocoaPods projects. - App Tracking Transparency helper on iOS (
requestTrackingAuthorization,getTrackingAuthorizationStatus). - GDPR, CCPA and COPPA signals through LevelPlay's privacy settings API, settable before init.
- Integration Test Suite and integration validation (
launchTestSuite,validateIntegration) for checking adapters during development. - Typed events (
loaded,loadFailed,displayed,displayFailed,clicked,closed,rewarded) with ad info including impression revenue. - Banners (0.3.0): standard sizes, adaptive (follows the safe-area width and rotation), and custom sizes; placed at
the top, bottom or centre with offsets, inside the safe area, in a pass-through overlay above the WebView (touches
beside a banner reach the page). Several banners at once, addressed by
bannerId. - Native ads (0.3.0): the plugin's
smallandmediumtemplates, styled from JS (colours, corner radius, fonts) and placed over any rectangle of the page, typically a placeholder element'sgetBoundingClientRect(). - Impression-level revenue (0.3.0):
impressionDatafor rewarded, interstitial, banner and native ads, queued (up to 100) until the first listener so early impressions are not lost;adInfoChangedfor full-screen ads. - Segments, dynamic user id, placement capping and rewards (0.3.0):
setSegment,setDynamicUserId,isPlacementCapped,getReward. - Capabilities (0.3.0):
getCapabilities()tells what the current platform supports. - Demo ids (
LEVELPLAY_DEMO) from Unity's public sample apps for test ads during development. - Web stub: on the web nothing is ever ready and shows resolve
{ shown: false }, so the same game code runs in a browser.
Compatibility
| | Version |
|---|---|
| Capacitor | 7 and 8 (@capacitor/core >= 7.0.0) |
| Unity LevelPlay SDK | 9.6.1 (Android com.unity3d.ads-mediation:mediation-sdk:9.6.1; iOS LevelPlay-Swift-Package 9.6.1 up to < 10, or the IronSourceSDK ~> 9.6.1 pod) |
| iOS | 14.0+ deployment target (Capacitor 7 default; Capacitor 8 apps use 15.0) |
| Xcode | 16+ for Capacitor 7, 26+ for Capacitor 8; tested with Xcode 27 (which needs an app target of iOS 15.0+) |
| Android | minSdk 23+, compileSdk / targetSdk 35 (Capacitor 7) or 36 (Capacitor 8), taken from the app's variables.gradle |
| Java | JDK 21 for Gradle builds |
| Node.js | 20+ (Capacitor 7 CLI), 22+ (Capacitor 8 CLI) |
| Plugin | Capacitor | LevelPlay SDK | |---|---|---| | 0.3.x | 7, 8 | 9.6.1 | | 0.2.x | 8 | 9.6.1 | | 0.1.x | 8 | 9.6.1 |
Install
npm install capacitor-levelplay
npx cap syncbun add capacitor-levelplay && bunx cap sync
yarn add capacitor-levelplay && yarn cap sync
pnpm add capacitor-levelplay && pnpm cap synciOS setup
Swift Package Manager (default)
Capacitor 8 projects (and Capacitor 7 projects created with --packagemanager SPM) need nothing extra: npx cap sync adds the plugin to CapApp-SPM/Package.swift
and Xcode resolves the LevelPlay package (a binary xcframework, roughly 27 MB) on the next build.
CocoaPods (alternative)
CocoaPods projects get the CapacitorLevelplay pod from npx cap sync; it depends on Capacitor and
IronSourceSDK ~> 9.6.1. Run pod install (or npx cap sync ios) as usual. Mediation adapters are then added as pods
(IronSource<Network>Adapter) in the app's Podfile.
-ObjC linker flag
LevelPlay requires it: App target > Build Settings > Linking > Other Linker Flags > add -ObjC.
Info.plist
<!-- App Tracking Transparency prompt text (requestTrackingAuthorization). -->
<key>NSUserTrackingUsageDescription</key>
<string>Your data will be used to deliver ads that are more relevant to you.</string>
<!-- SKAdNetwork ids: LevelPlay's own id plus the ids of every network you mediate (see below). -->
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>su67r6k2v3.skadnetwork</string>
</dict>
<!-- ... -->
</array>
<!-- Recommended: copies of winning SKAdNetwork install-validation postbacks. -->
<key>NSAdvertisingAttributionReportEndpoint</key>
<string>https://postbacks-is.com/</string>
<!-- LevelPlay's integration guide asks for arbitrary loads (some ad creatives are served over http). -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>Generating SKAdNetworkItems. su67r6k2v3.skadnetwork is LevelPlay's (ironSource Ads) id. Every mediated network
needs its own ids as well. Use Unity's SKAdNetwork ID manager
to export the combined list for the networks you enable, or merge each network's official list yourself (for example
Unity Ads publishes https://skan.mz.unity3d.com/v3/partner/skadnetworks.plist.json). A small script that downloads
the lists, extracts every xxxxxxxxxx.skadnetwork id, de-duplicates them and rewrites the SKAdNetworkItems array keeps
this repeatable; re-run it whenever you add a network and before each release. Some lists also carry AdAttributionKit
ids (.adattributionkit), which go into the AdNetworkIdentifiers array.
Full checklist: Unity's iOS SDK integration guide.
Android setup
Nothing beyond npx cap sync for most apps:
- Repositories: the SDK and all LevelPlay adapters are on Maven Central. Capacitor's default
android/build.gradlealready listsgoogle()andmavenCentral(); keep both. - Permissions: the plugin's manifest adds
com.google.android.gms.permission.AD_ID(required for the advertising id on Android 13+). The SDK's own manifest bringsINTERNET,ACCESS_NETWORK_STATE, its activities and providers. A child-directed app can stripAD_IDfrom its manifest withtools:node="remove". - Dependencies: the plugin module declares
mediation-sdkplus the Play servicesads-identifier,appsetandbasementartifacts the LevelPlay guide asks for. - ProGuard / R8: the core keep rules ship as consumer rules. If you minify, add the per-network rules from Unity's Android SDK integration guide for each adapter you add.
Optional: pin a different 9.x SDK from the app's android/variables.gradle:
ext {
levelPlayVersion = '9.6.1'
}Gradle in Capacitor 7 and 8 projects needs JDK 21 (see Troubleshooting).
Quick start
import { Capacitor } from '@capacitor/core';
import { LevelPlay, LEVELPLAY_DEMO } from 'capacitor-levelplay';
// Unity's public demo ids serve test ads. Replace them with your own before release.
const ids = Capacitor.getPlatform() === 'ios' ? LEVELPLAY_DEMO.ios : LEVELPLAY_DEMO.android;
export async function startAds(): Promise<void> {
await LevelPlay.requestTrackingAuthorization(); // iOS ATT prompt; resolves 'unavailable' elsewhere
await LevelPlay.initialize({
appKey: ids.appKey,
consent: { gdprConsent: false }, // until your CMP says otherwise, see "Privacy and consent"
});
await LevelPlay.loadRewarded({ adUnitId: ids.rewarded });
await LevelPlay.loadInterstitial({ adUnitId: ids.interstitial });
}
export async function watchVideoForCoins(): Promise<number> {
const result = await LevelPlay.showRewarded({ adUnitId: ids.rewarded });
void LevelPlay.loadRewarded({ adUnitId: ids.rewarded }); // preload the next one
return result.rewarded ? (result.reward?.amount ?? 0) : 0;
}Usage guide
Initialise with consent
Initialise once, as early as is sensible, after consent is known (and on iOS after the ATT prompt). Ads can only be
loaded after initialize resolves.
const { status } = await LevelPlay.requestTrackingAuthorization(); // iOS only, see Privacy and consent
const { sdkVersion } = await LevelPlay.initialize({
appKey: ids.appKey,
userId: playerId, // optional: needed for server-to-server reward callbacks
consent: {
gdprConsent: cmpSaysYes, // EEA / UK / CH users: false until a CMP collected consent
ccpaDoNotSell: false, // true if a US user opted out of sale / sharing
coppa: false, // true for child-directed treatment
},
});initialize rejects with the SDK's init error (code, message); you can call it again later. Calling it after a
successful init resolves immediately, and concurrent calls share one init.
Rewarded ads
const REWARDED = ids.rewarded;
await LevelPlay.loadRewarded({ adUnitId: REWARDED });
// When the player taps "Watch a video":
const { ready } = await LevelPlay.isReady({ format: 'rewarded', adUnitId: REWARDED });
if (!ready) {
showToast('No video available right now');
} else {
const result = await LevelPlay.showRewarded({ adUnitId: REWARDED, placementName: 'DoubleCoins' });
if (result.rewarded && result.reward) {
grant(result.reward.name, result.reward.amount);
} else if (result.error) {
console.warn('rewarded not shown', result.error.code, result.error.message);
}
await LevelPlay.loadRewarded({ adUnitId: REWARDED }); // always load the next one
}- The show promise resolves after the ad closes (or failed to display).
- Grant the reward only when
rewardedistrue. The reward and close callbacks can arrive in either order on some networks; the plugin waits up to 1 second after the close for a late reward before resolving. - When the ad is not ready, the promise resolves
{ shown: false, rewarded: false, error: { code: -1, message: 'Ad not ready' } }. placementNameis optional and refers to a placement configured in the LevelPlay dashboard (capping, pacing, reward).- For server-side rewards, pass
userIdtoinitializeand configure server-to-server callbacks in the dashboard.
Interstitial ads
await LevelPlay.loadInterstitial({ adUnitId: ids.interstitial });
// At a natural break, for example between levels:
const result = await LevelPlay.showInterstitial({ adUnitId: ids.interstitial });
// result.shown tells you whether it was displayed; game flow continues after the close.
void LevelPlay.loadInterstitial({ adUnitId: ids.interstitial });Listening to events
Load results arrive only as events, so listen for loaded / loadFailed if you want to drive UI or retry logic.
import type { PluginListenerHandle } from '@capacitor/core';
const handles: PluginListenerHandle[] = [
await LevelPlay.addListener('loaded', (e) => console.log('loaded', e.format, e.adUnitId, e.adInfo?.adNetwork)),
await LevelPlay.addListener('loadFailed', (e) => {
console.warn('load failed', e.format, e.error.code, e.error.message);
setTimeout(() => {
void (e.format === 'rewarded'
? LevelPlay.loadRewarded({ adUnitId: e.adUnitId })
: LevelPlay.loadInterstitial({ adUnitId: e.adUnitId }));
}, 30_000); // retry later; use an increasing backoff in production
}),
await LevelPlay.addListener('displayed', (e) => trackImpression(e.adInfo?.revenue, e.adInfo?.adNetwork)),
await LevelPlay.addListener('rewarded', (e) => console.log('reward', e.reward.name, e.reward.amount)),
await LevelPlay.addListener('closed', (e) => resumeAudio()),
];
// later
await Promise.all(handles.map((h) => h.remove()));
// or: await LevelPlay.removeAllListeners();Every event carries { format: 'rewarded' | 'interstitial', adUnitId, adInfo? }, plus error on loadFailed /
displayFailed and reward on rewarded.
Checking readiness
isReady({ format, adUnitId }) returns the native isAdReady() for that ad unit. It is false for an ad unit that was
never loaded. Use it to enable or disable a "watch video" button.
Banners
A banner is created hidden, then loaded and shown. createBanner resolves the banner's size and on-screen frame (CSS
px, relative to the WebView viewport), so the page can leave room for it.
const banner = await LevelPlay.createBanner({
adUnitId: ids.banner,
bannerId: 'main', // optional; defaults to adUnitId
size: 'ADAPTIVE', // BANNER 320x50, LARGE 320x90, MEDIUM_RECTANGLE 300x250, LEADERBOARD 728x90, ADAPTIVE, CUSTOM
position: 'bottom', // 'top' | 'bottom' | 'center'
offsetY: 0, // CSS px, away from the edge
respectSafeArea: true, // default: stays clear of notches, status bar, navigation bar and home indicator
});
document.body.style.paddingBottom = `${banner.frame.height}px`;
await LevelPlay.addListener('bannerLoaded', (e) => console.log('banner', e.bannerId, e.frame));
await LevelPlay.addListener('bannerLoadFailed', (e) => console.warn('banner failed', e.error.code));
await LevelPlay.loadBanner({ bannerId: 'main' }); // once per banner object; the SDK refreshes and retries by itself
await LevelPlay.showBanner({ bannerId: 'main' });
await LevelPlay.setBannerLayout({ bannerId: 'main', position: 'top' }); // move it
await LevelPlay.hideBanner({ bannerId: 'main' }); // hidden banners pause auto refresh
await LevelPlay.destroyBanner({ bannerId: 'main' });ADAPTIVEuses the safe-area width (oradaptiveWidthin CSS px) and is recreated and reloaded automatically when that width changes, for example on rotation, keeping its id, position and visibility.CUSTOMtakescustomSize: { width, height }in CSS px.- Banner events:
bannerLoaded,bannerLoadFailed,bannerDisplayed,bannerDisplayFailed,bannerClicked,bannerExpanded,bannerCollapsed,bannerLeftApplication, all with{ bannerId, adUnitId, adInfo?, frame? }.
| Top and bottom (Android) | Rotated, adaptive (Android) |
|---|---|
|
|
|
Native ads
Native ads are drawn by the plugin's templates (small: a row at least 90 px tall, no media; medium: with a media
view, about 300 x 350) and placed over a
rectangle of the page, usually a placeholder element. Check getCapabilities() first.
const caps = await LevelPlay.getCapabilities();
if (caps.nativeAd && caps.nativeAdTemplates.includes('small')) {
const slot = document.getElementById('native-slot')!; // e.g. a 90 px tall div
await LevelPlay.addListener('nativeAdLoaded', async (e) => {
const r = slot.getBoundingClientRect();
await LevelPlay.showNativeAd({ nativeAdId: e.nativeAdId, rect: { x: r.left, y: r.top, width: r.width, height: r.height } });
});
await LevelPlay.addListener('nativeAdLoadFailed', (e) => console.warn('native failed', e.error.code));
await LevelPlay.loadNativeAd({
nativeAdId: 'feed-1',
template: 'small',
placementName: 'Feed', // optional
style: {
backgroundColor: '#ffffff',
titleColor: '#111111',
bodyColor: '#555555',
callToActionBackgroundColor: '#2f6fed',
callToActionTextColor: '#ffffff',
cornerRadius: 8,
titleFont: { family: 'fonts/Inter-SemiBold.ttf', size: 15 }, // a web asset path or a system family
bodyFont: { size: 13 },
callToActionFont: { family: 'Helvetica', size: 14 },
},
});
}
// keep it on the placeholder while the page scrolls or resizes
await LevelPlay.setNativeAdRect({ nativeAdId: 'feed-1', rect: { x: 16, y: 420, width: 343, height: 90 } });
await LevelPlay.hideNativeAd({ nativeAdId: 'feed-1' });
await LevelPlay.destroyNativeAd({ nativeAdId: 'feed-1' });Style options (NativeAdTemplateStyle): backgroundColor, titleColor, bodyColor, callToActionBackgroundColor,
callToActionTextColor (#RRGGBB or #RRGGBBAA), cornerRadius (CSS px), and titleFont, bodyFont, callToActionFont
({ family?, size? }; a .ttf / .otf path is read from the app's web assets, anything else is a system font family;
a missing font falls back to the system font). The template texts "Ad" and "Open" can be localised with the app
resources levelplay_native_ad_badge and levelplay_native_ad_cta_fallback (Android strings.xml, iOS
Localizable.strings).
Native events: nativeAdLoaded, nativeAdLoadFailed, nativeAdImpression, nativeAdClicked, all with
{ nativeAdId, placementName?, adInfo? }.
Impression-level revenue
await LevelPlay.addListener('impressionData', (d) => {
// d.adFormat as the SDK reports it ('Rewarded Video', 'Interstitial', 'Banner', 'nativead' ...); d.revenue in USD
analytics.logAdImpression({ network: d.adNetwork, format: d.adFormat, revenue: d.revenue ?? 0, currency: 'USD' });
});Impressions that happen before the first listener (for example a banner shown during app start) are queued, up to 100,
and delivered in order when the first impressionData listener is added. d.allData carries every raw field of the
SDK's impression object. adInfoChanged fires when the ad info of a loaded rewarded or interstitial ad changes.
Segments, user id, placements
await LevelPlay.setSegment({ segmentName: 'whales', level: 12, isPaying: true, iapTotal: 49.99, customParameters: { cohort: 'b' } });
await LevelPlay.setDynamicUserId({ userId: 'player-123' }); // { valid } ; used for server-to-server rewards
const { capped } = await LevelPlay.isPlacementCapped({ format: 'rewarded', placementName: 'Shop' });
const reward = await LevelPlay.getReward({ adUnitId: ids.rewarded, placementName: 'Shop' }); // { name, amount }
await LevelPlay.showRewarded({ adUnitId: ids.rewarded, placementName: 'Shop' });setSegment takes at most 5 custom parameters, keys and values 1-32 letters and digits (SDK limits); invalid input
rejects with INVALID_ARGUMENT instead of being dropped silently by the SDK.
Error codes
Calls reject with a code: INVALID_ARGUMENT, NOT_INITIALIZED (banner / native before initialize()),
ALREADY_EXISTS (banner id in use), NOT_FOUND (unknown banner or native id), NOT_LOADED (showNativeAd before
nativeAdLoaded), UNSUPPORTED, NO_ACTIVITY (Android) / NO_VIEW_CONTROLLER (iOS), UNIMPLEMENTED (web).
hideBanner and the destroy* calls resolve for unknown ids. Ad load and show errors arrive in events as
{ code, message } with the SDK's code (509 is "no fill").
Integration Test Suite
The Integration Test Suite shows every configured network, its adapter status and lets you request test ads per network.
await LevelPlay.initialize({ appKey: ids.appKey, testSuite: true }); // sets is_test_suite=enable before init
await LevelPlay.launchTestSuite();Development builds only. Unity recommends not calling other LevelPlay APIs before launching the suite, and the suite supports portrait orientation only.
Validate the integration
await LevelPlay.validateIntegration();Writes LevelPlay's integration helper report to the native log: the Xcode console on iOS, logcat tag
IntegrationHelper on Android (adb logcat | grep IntegrationHelper). Each network is listed with its adapter and SDK
version and VERIFIED when everything is in place. Remove the call from release builds.
Meta data
Network-specific and SDK flags go through setMetaData before init, for example:
await LevelPlay.setMetaData({ key: 'is_deviceid_optout', value: 'true' });Demo ids
LEVELPLAY_DEMO holds the public app keys and ad unit ids from Unity's official sample apps
(Mediation-Demo-Apps). They serve test ads; never ship
them.
| Platform | App key | Rewarded | Interstitial | Banner |
|---|---|---|---|---|
| Android | 25b63cf85 | syz3d8ekts22q0or | h3xw38h9214adgxo | 4fpetq4lhe5lsw3e |
| iOS | 8545d445 | qwouvdrkuwivay5q | wmgt0712uuux8ju4 | iep3rxsyp9na3rw8 |
The sample apps have no native ad unit; native ads load with the app key's default placement.
Web
LevelPlay has no web SDK. On the web initialize and launchTestSuite reject as unimplemented, isReady is always
false and shows resolve { shown: false, rewarded: false, error: { code: -1, ... } }. getCapabilities() reports
nothing supported; createBanner, showBanner, setBannerLayout, loadNativeAd and showNativeAd reject as
unimplemented; setSegment, loadBanner, hide and destroy calls are no-ops; setDynamicUserId resolves
{ valid: false }, isPlacementCapped { capped: false } and getReward { name: '', amount: 0 }.
Example app
example-app/ is a minimal Capacitor 8 app (HTML + TypeScript) that uses the plugin from this
repository with the demo ids: initialize, rewarded, interstitial, banner top / bottom / hide / destroy, native small /
medium, segment and an impression log. See its README for the steps.
Mediation adapters
The plugin brings the LevelPlay SDK (which includes ironSource Ads). Every other network is an adapter plus that network's SDK, added to your app, not to the plugin. Pick versions from Unity's adapter tables (Android, iOS) and take each adapter together with the network SDK version it was built for (the adapter changelog says "Supporting SDK version ..."). Then enable the network in the LevelPlay dashboard.
Android (Gradle)
Adapters live on Maven Central under com.unity3d.ads-mediation:<network>-adapter:<version>. Add each adapter and the
network SDK to android/app/build.gradle:
dependencies {
// Unity Ads
implementation 'com.unity3d.ads-mediation:unityads-adapter:<adapter version>'
implementation 'com.unity3d.ads:unity-ads:<sdk version>'
// Liftoff Monetize (Vungle)
implementation 'com.unity3d.ads-mediation:vungle-adapter:<adapter version>'
implementation 'com.vungle:vungle-ads:<sdk version>'
}List the network SDK explicitly: the adapter artifacts do not pull it in. Some networks need more (Google AdMob, for
example, needs its com.google.android.gms.ads.APPLICATION_ID meta-data in AndroidManifest.xml, or the app crashes at
launch); check the network's page in Unity's docs.
iOS (Swift Package Manager)
Unity publishes official adapter packages on GitHub as
https://github.com/ironsource-mobile/LevelPlay-<Network>-Adapter-Swift-Package (for example
LevelPlay-UnityAds-Adapter-Swift-Package, LevelPlay-Vungle-Adapter-Swift-Package). In Xcode: File > Add Package
Dependencies, enter the URL, choose an exact version and add the product to the App target. Each package pulls
its network SDK and LevelPlay-Swift-Package 9.x, which resolves to the same copy the plugin uses.
Networks without an official Swift package. Not every network has one (at the time of writing, InMobi does not). Two options:
Use CocoaPods for the project and add the
IronSource<Network>Adapterpod.Keep SPM and wrap the adapter in a small local Swift package that mirrors the official packages: a
binaryTargetpointing at the adapter zip Unity publishes for CocoaPods (the URL is in the adapter's podspec, pin its SHA-256 withswift package compute-checksum), a dependency on the network's own Swift package at the version the adapter supports, a dependency onLevelPlay-Swift-Package9.x, and an empty Swift source file for the wrapper target. Add the local package to the App target via Add Package Dependencies > Add Local....// swift-tools-version: 5.9 import PackageDescription let package = Package( name: "LevelPlay-Example-Adapter", platforms: [.iOS(.v13)], products: [.library(name: "ExampleAdapter", targets: ["ExampleAdapter"])], dependencies: [ .package(url: "https://github.com/<network>/<Network>SDK-Swift-Package.git", exact: "<sdk version>"), .package(url: "https://github.com/ironsource-mobile/LevelPlay-Swift-Package.git", "9.0.0"..<"10.0.0"), ], targets: [ .target( name: "ExampleAdapter", // Sources/ExampleAdapter/ExampleAdapter.swift can be empty dependencies: [ "ExampleAdapterBinary", .product(name: "<NetworkSDK product>", package: "<Network>SDK-Swift-Package"), .product(name: "UnityMediationSDK", package: "LevelPlay-Swift-Package"), ]), .binaryTarget( name: "ExampleAdapterBinary", url: "<adapter zip URL from the adapter podspec>", checksum: "<sha256>"), ] )Add any system libraries the network's manual-integration guide lists as
linkerSettings.
After adding networks: update SKAdNetworkItems (iOS setup), rebuild both platforms and run
validateIntegration().
Privacy and consent
LevelPlay recommends setting privacy signals before initialize. Pass them as consent to initialize or call
setConsent first; call setConsent again whenever the user changes their choice. They map to
LevelPlayPrivacySettings (Android) and LPMPrivacySettings (iOS): setGDPRConsent, setCCPA, setCOPPA. See
Unity's regulation settings.
- GDPR (EEA, UK, Switzerland): pass
gdprConsent: falseuntil a consent management platform (CMP) collected consent, thentrueorfalseaccording to the user's choice. If you use an IAB TCF v2 CMP (for example Google UMP), LevelPlay and many networks also read the TCF consent string the CMP stores on the device. - CCPA and other US state laws:
ccpaDoNotSell: truewhen the user opted out of the sale or sharing of personal data. - COPPA:
coppa: truefor users who must get child-directed treatment. Child-directed apps should also strip theAD_IDpermission on Android and should not show the ATT prompt.
App Tracking Transparency (iOS)
Without ATT authorization the IDFA is zeros and ads earn less, so ask before init:
- Add
NSUserTrackingUsageDescriptiontoInfo.plist. - Call
requestTrackingAuthorization()when the app is active (iOS ignores the request while the app is still launching or in the background) and beforeinitialize. Show your CMP first if you have one. - iOS shows the system prompt only once; later calls resolve the stored status. Use
getTrackingAuthorizationStatus()to read it without prompting.
const { status } = await LevelPlay.getTrackingAuthorizationStatus();
if (status === 'notDetermined') await LevelPlay.requestTrackingAuthorization();
await LevelPlay.initialize({ appKey });Limitations
- Native ads need per-network setup. Only networks that serve native ads through LevelPlay fill them, and each needs its adapter and a native ad configuration in the dashboard. The public demo app key has no native configuration on Android (508 "No Native Ad configurations found"); on iOS it filled from ironSource Ads in testing.
- Native ads use the plugin's templates. Custom native layouts in HTML are not possible: the SDK requires its own native views (and the network's privacy icon) to record impressions and clicks.
loadBanneris one-shot per banner object (an SDK rule in 9.6.1): a second call is ignored and the SDK retries on its refresh interval. To retry right away,destroyBanner+createBanner+loadBanner.-ObjCis required on iOS, also for the new APIs: without itsetSegmentcrashes with an unrecognized selector.- No
adInfoChangedfor banners and native ads: the SDK only reports it for rewarded and interstitial ads. lifetimeRevenueis not typed inImpressionData; read it fromallData.lifetimeRevenuewhen present.- Overlay ads: banners and native ads are native views above the WebView, so CSS cannot clip, transform or
animate them; move them with
setBannerLayout/setNativeAdRectand hide them under your own modals.
Troubleshooting
Loads fail with 509 "No fill"
Common and usually not a bug. An app that is not live in its store yet (or not approved in the LevelPlay dashboard)
gets little or no real demand. Use the demo ids (LEVELPLAY_DEMO) or the Integration Test Suite with test ads to
check your integration, and retry loads with a backoff in production. Unity's
troubleshooting guide lists
more causes.
Unity Ads: "Invalid Game ID"
The Unity Ads adapter is started with the game id configured on the Unity Ads instance in LevelPlay. If Unity Ads answers "Invalid Game ID: ..." (iOS: "Initialization failed: not found"), the Unity Ads project or game is not active, or the instance uses a game id from another project. Check the game ids in the Unity dashboard and that they belong to the project linked to your LevelPlay app.
Android build fails with "Unsupported class file major version"
Gradle for Capacitor 8 must run on JDK 21. Android Studio's bundled runtime can be newer than the Gradle version supports (for example "Unsupported class file major version 69" with Java 25). Point Gradle at a JDK 21:
export JAVA_HOME=$(/usr/libexec/java_home -v 21) # macOS
cd android && ./gradlew assembleDebugIn Android Studio: Settings > Build, Execution, Deployment > Build Tools > Gradle > Gradle JDK.
iOS: "No such module 'IronSource'" or the package does not update
- Run
npx cap sync iosafter every install or upgrade of the plugin; it rewritesCapApp-SPM/Package.swift. - In Xcode: File > Packages > Reset Package Caches, then Resolve Package Versions.
- Still stuck: quit Xcode, delete
~/Library/Developer/Xcode/DerivedData/<App>-*and~/Library/Caches/org.swift.swiftpm, then reopen. - CocoaPods projects:
cd ios/App && pod install --repo-update.
iOS: crash or missing symbols at launch
Check the -ObjC linker flag on the App target.
Nothing happens on showRewarded
showRewarded resolves { shown: false, error: { code: -1, message: 'Ad not ready' } } when no ad is loaded for that ad
unit. Make sure you called loadRewarded with the same adUnitId after initialize resolved, and wait for the
loaded event (or isReady).
FAQ
Which LevelPlay API does it use?
LevelPlay's ad-unit API, the current API in SDK 9.x: LevelPlay.init with an init request,
LevelPlayRewardedAd / LevelPlayInterstitialAd on Android and LPMRewardedAd / LPMInterstitialAd on iOS. The
legacy IronSource.* placement API is not used.
Can I use more than one ad unit per format?
Yes. Every call takes an adUnitId, and the plugin keeps one native ad object per id.
Does it support banners or native ads? Yes, since 0.3.0: banners in every LevelPlay size (including adaptive and custom sizes) and native ads in two templates. See Banners and Native ads.
Does it work with Capacitor 7?
Yes, since 0.3.0 (@capacitor/core >= 7.0.0). Android and iOS (Swift Package Manager) builds were checked with a
Capacitor 7.6.9 app.
How is this different from capacitor-levelplay-ads?
Both are Capacitor plugins for LevelPlay and both use the ad-unit API. The differences, as of capacitor-levelplay-ads
0.1.42:
| | capacitor-levelplay | capacitor-levelplay-ads |
|---|---|---|
| iOS integration | SPM first: Package.swift depends on LevelPlay-Swift-Package; podspec as alternative | CocoaPods first; its Package.swift does not depend on the SDK (SDK code is compiled out unless you add a package yourself) |
| Formats | rewarded, interstitial, banner, native (templates) | banner, rewarded, interstitial |
| Ad units | any number per format side by side, addressed by adUnitId | one ad object per format at a time |
| Show result | promise resolves after close with { shown, rewarded, reward } | outcome via events |
| Consent | GDPR / CCPA / COPPA flags; bring your own CMP | built-in consent flows (own consent modal, optional Usercentrics / InMobi CMP) |
| Adapters | added by the app (Gradle / Swift packages / pods) | helper script that injects adapter pods from package.json |
Pick the one that fits your project.
Is the LevelPlay SDK bundled? No. The plugin declares the SDK as a dependency (Maven Central, Swift package or pod). The SDK is proprietary and covered by Unity's terms.
API
initialize(...)getSdkVersion()setConsent(...)setMetaData(...)requestTrackingAuthorization()getTrackingAuthorizationStatus()loadRewarded(...)showRewarded(...)loadInterstitial(...)showInterstitial(...)isReady(...)launchTestSuite()validateIntegration()getCapabilities()setSegment(...)setDynamicUserId(...)isPlacementCapped(...)getReward(...)createBanner(...)loadBanner(...)showBanner(...)hideBanner(...)setBannerLayout(...)destroyBanner(...)loadNativeAd(...)showNativeAd(...)setNativeAdRect(...)hideNativeAd(...)destroyNativeAd(...)addListener('loaded', ...)addListener('loadFailed', ...)addListener('displayed', ...)addListener('displayFailed', ...)addListener('clicked', ...)addListener('closed', ...)addListener('rewarded', ...)addListener('adInfoChanged', ...)addListener('impressionData', ...)addListener('bannerLoaded', ...)addListener('bannerLoadFailed', ...)addListener('bannerDisplayed', ...)addListener('bannerDisplayFailed', ...)addListener('bannerClicked', ...)addListener('bannerExpanded', ...)addListener('bannerCollapsed', ...)addListener('bannerLeftApplication', ...)addListener('nativeAdLoaded', ...)addListener('nativeAdLoadFailed', ...)addListener('nativeAdImpression', ...)addListener('nativeAdClicked', ...)removeAllListeners()- Interfaces
- Type Aliases
Unity LevelPlay ads (ad-unit API): rewarded, interstitial and (since 0.3.0) banner and native ads, impression-level revenue, segments and placement capping.
initialize(...)
initialize(options: InitOptions) => Promise<InitResult>Initialise the LevelPlay SDK (LevelPlay.init). Resolves on init success, rejects with the init error
(code and message from the SDK) otherwise. Calling it again after a successful init resolves immediately;
concurrent calls share one init. Load ads only after this resolves.
Set consent (and on iOS ask for ATT) before calling it.
On the web it rejects as unimplemented.
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | InitOptions |
Returns: Promise<InitResult>
Since: 0.1.0
getSdkVersion()
getSdkVersion() => Promise<InitResult>Native LevelPlay SDK version. Works before init.
Returns: Promise<InitResult>
Since: 0.1.0
setConsent(...)
setConsent(options: ConsentOptions) => Promise<void>Forward GDPR / CCPA / COPPA signals to LevelPlay. Call it before initialize() when you
can, and again whenever the user changes their choice.
| Param | Type |
| ------------- | --------------------------------------------------------- |
| options | ConsentOptions |
Since: 0.1.0
setMetaData(...)
setMetaData(options: MetaDataOptions) => Promise<void>Raw LevelPlay.setMetaData(key, value) for SDK or network-specific flags. Call it before init.
| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | MetaDataOptions |
Since: 0.1.0
requestTrackingAuthorization()
requestTrackingAuthorization() => Promise<TrackingResult>iOS: show the App Tracking Transparency prompt and resolve with the resulting status. Needs
NSUserTrackingUsageDescription in Info.plist. iOS only shows the prompt once; later calls resolve the stored
status. Call it before initialize(), while the app is active.
Android and web: resolves unavailable.
Returns: Promise<TrackingResult>
Since: 0.1.0
getTrackingAuthorizationStatus()
getTrackingAuthorizationStatus() => Promise<TrackingResult>Current App Tracking Transparency status without prompting (iOS). Android and web: unavailable.
Returns: Promise<TrackingResult>
Since: 0.1.0
loadRewarded(...)
loadRewarded(options: AdUnitOptions) => Promise<void>Start loading a rewarded ad for the ad unit. The native ad object is created on first use and reused for the
ad unit. Resolves once the request is issued; the outcome arrives as a loaded or loadFailed event.
Load the next ad after each show.
| Param | Type |
| ------------- | ------------------------------------------------------- |
| options | AdUnitOptions |
Since: 0.1.0
showRewarded(...)
showRewarded(options: ShowOptions) => Promise<ShowResult>Show a loaded rewarded ad. Resolves after the ad closed (or failed to display) with what happened. The reward
and close callbacks can arrive in either order on some networks, so the plugin waits up to 1 second after the close
for a late reward. Never rejects for "not ready": resolves { shown: false, rewarded: false, error } instead.
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | ShowOptions |
Returns: Promise<ShowResult>
Since: 0.1.0
loadInterstitial(...)
loadInterstitial(options: AdUnitOptions) => Promise<void>Start loading an interstitial ad for the ad unit. Works like loadRewarded().
| Param | Type |
| ------------- | ------------------------------------------------------- |
| options | AdUnitOptions |
Since: 0.1.0
showInterstitial(...)
showInterstitial(options: ShowOptions) => Promise<ShowResult>Show a loaded interstitial. Resolves after it closed (or failed to display). Never rejects for "not ready".
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | ShowOptions |
Returns: Promise<ShowResult>
Since: 0.1.0
isReady(...)
isReady(options: IsReadyOptions) => Promise<IsReadyResult>isAdReady() of the native ad object for this ad unit. false when the ad unit was never loaded.
| Param | Type |
| ------------- | --------------------------------------------------------- |
| options | IsReadyOptions |
Returns: Promise<IsReadyResult>
Since: 0.1.0
launchTestSuite()
launchTestSuite() => Promise<void>Open the LevelPlay Integration Test Suite. Requires initialize({ testSuite: true }) first.
Development builds only. Rejects on the web.
Since: 0.1.0
validateIntegration()
validateIntegration() => Promise<void>Write the LevelPlay integration helper report to the native log (Xcode console; Android logcat tag
IntegrationHelper): SDK, adapter and network SDK versions, each VERIFIED or not. Development only.
Since: 0.1.0
getCapabilities()
getCapabilities() => Promise<Capabilities>What this platform supports (banners, native ad templates, impression data, adInfoChanged). Works before init.
Web: everything false.
Returns: Promise<Capabilities>
Since: 0.3.0
setSegment(...)
setSegment(options: SegmentOptions) => Promise<void>Set the user segment (LevelPlay.setSegment with a LevelPlaySegment / LPMSegment). Call it before
initialize() so the first ad requests use it; later calls apply to the following requests. Rejects with
INVALID_ARGUMENT when customParameters break the SDK limits. Web: no-op.
| Param | Type |
| ------------- | --------------------------------------------------------- |
| options | SegmentOptions |
Since: 0.3.0
setDynamicUserId(...)
setDynamicUserId(options: DynamicUserIdOptions) => Promise<DynamicUserIdResult>Set or change the dynamic user id used in server-to-server reward callbacks (LevelPlay.setDynamicUserId on
both platforms). Set it before showRewarded(). Web: resolves { valid: false }.
| Param | Type |
| ------------- | --------------------------------------------------------------------- |
| options | DynamicUserIdOptions |
Returns: Promise<DynamicUserIdResult>
Since: 0.3.0
isPlacementCapped(...)
isPlacementCapped(options: PlacementCappedOptions) => Promise<PlacementCappedResult>Whether a rewarded or interstitial placement is capped right now (static
LevelPlayRewardedAd.isPlacementCapped / LevelPlayInterstitialAd.isPlacementCapped on Android,
LPMRewardedAd.isPlacementCapped: / LPMInterstitialAd.isPlacementCapped: on iOS). Works without a loaded ad.
Web: { capped: false }.
| Param | Type |
| ------------- | ------------------------------------------------------------------------- |
| options | PlacementCappedOptions |
Returns: Promise<PlacementCappedResult>
Since: 0.3.0
getReward(...)
getReward(options: GetRewardOptions) => Promise<Reward>The reward configured for a rewarded ad unit or one of its placements (LevelPlayRewardedAd.getReward(placement) /
LPMRewardedAd getReward(placementName:)), for "watch a video for N coins" buttons. The SDK returns
{ name: '', amount: 0 } when it has no reward configuration (for example before init). Web: the same empty
reward.
| Param | Type |
| ------------- | ------------------------------------------------------------- |
| options | GetRewardOptions |
Returns: Promise<Reward>
Since: 0.3.0
createBanner(...)
createBanner(options: CreateBannerOptions) => Promise<BannerResult>Create a banner (LevelPlayBannerAdView / LPMBannerAdView) for the ad unit and attach it, hidden, in a
pass-through overlay above the WebView. Requires a finished initialize() (NOT_INITIALIZED otherwise). Rejects
with ALREADY_EXISTS when bannerId is in use; destroy it first. Does not load: call loadBanner().
Web: rejects as unimplemented.
| Param | Type |
| ------------- | ------------------------------------------------------------------- |
| options | CreateBannerOptions |
Returns: Promise<BannerResult>
Since: 0.3.0
loadBanner(...)
loadBanner(options: BannerIdOptions) => Promise<void>Load the banner (loadAd() / loadAdWithViewController:). The outcome arrives as bannerLoaded or
bannerLoadFailed; after the first load the SDK refreshes the banner on the dashboard interval. The SDK accepts
one load per banner object: calling it again has no effect (Android logs "Banner load already called"), so to retry
right away after bannerLoadFailed, destroy the banner and create it again. Web: no-op.
| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | BannerIdOptions |
Since: 0.3.0
showBanner(...)
showBanner(options: BannerIdOptions) => Promise<BannerResult>Make the banner visible and resume auto refresh (resumeAutoRefresh). Can be called before the load finished;
the creative appears when it arrives. Web: rejects as unimplemented.
| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | BannerIdOptions |
Returns: Promise<BannerResult>
Since: 0.3.0
hideBanner(...)
hideBanner(options: BannerIdOptions) => Promise<void>Hide the banner and pause auto refresh (pauseAutoRefresh) so hidden banners do not burn impressions. The view
stays attached; showBanner() brings it back. Web: no-op.
| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | BannerIdOptions |
Since: 0.3.0
setBannerLayout(...)
setBannerLayout(options: SetBannerLayoutOptions) => Promise<BannerResult>Move a banner (position, offsets, safe area). Resolves with the new frame. Web: rejects as unimplemented.
| Param | Type |
| ------------- | ------------------------------------------------------------------------- |
| options | SetBannerLayoutOptions |
Returns: Promise<BannerResult>
Since: 0.3.0
destroyBanner(...)
destroyBanner(options: BannerIdOptions) => Promise<void>Remove the banner from the screen and destroy() it. A destroyed banner cannot be reused; create a new one.
Resolves also for unknown ids. Web: no-op.
| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | BannerIdOptions |
Since: 0.3.0
loadNativeAd(...)
loadNativeAd(options: LoadNativeAdOptions) => Promise<void>Load a native ad into a slot. Following the SDK rule "one native ad object per load", it destroys the slot's
previous ad (hiding it if shown), builds a new LevelPlayNativeAd with the placement and loads it. The outcome
arrives as nativeAdLoaded or nativeAdLoadFailed. Requires a finished initialize(). Rejects with
UNSUPPORTED when getCapabilities().nativeAd is false or the template is not listed there. Web: rejects as
unimplemented.
| Param | Type |
| ------------- | ------------------------------------------------------------------- |
| options | LoadNativeAdOptions |
Since: 0.3.0
showNativeAd(...)
showNativeAd(options: NativeAdRectOptions) => Promise<void>Render the loaded native ad into its template, register the asset views with the SDK
(NativeAdLayout.registerNativeAdViews / ISNativeAdView registerNativeAdViews:) and place it at rect above the
WebView. Rejects with NOT_LOADED before nativeAdLoaded. The impression is reported by nativeAdImpression.
Web: rejects as unimplemented.
| Param | Type |
| ------------- | ------------------------------------------------------------------- |
| options | NativeAdRectOptions |
Since: 0.3.0
setNativeAdRect(...)
setNativeAdRect(options: NativeAdRectOptions) => Promise<void>Move or resize a shown native ad, for example after the placeholder element moved. Web: no-op.
| Param | Type |
| ------------- | ------------------------------------------------------------------- |
| options | NativeAdRectOptions |
Since: 0.3.0
hideNativeAd(...)
hideNativeAd(options: NativeAdIdOptions) => Promise<void>Hide a shown native ad (the view stays registered; showNativeAd() shows it again). Web: no-op.
| Param | Type |
| ------------- | --------------------------------------------------------------- |
| options | NativeAdIdOptions |
Since: 0.3.0
destroyNativeAd(...)
destroyNativeAd(options: NativeAdIdOptions) => Promise<void>Remove the native ad view and destroyAd() it. Resolves also for unknown ids. Web: no-op.
| Param | Type |
| ------------- | --------------------------------------------------------------- |
| options | NativeAdIdOptions |
Since: 0.3.0
addListener('loaded', ...)
addListener(eventName: 'loaded', listenerFunc: (event: AdEvent) => void) => Promise<PluginListenerHandle>An ad finished loading for the ad unit and can be shown.
| Param | Type |
| ------------------ | --------------------------------------------------------------- |
| eventName | 'loaded' |
| listenerFunc | (event: AdEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.1.0
addListener('loadFailed', ...)
addListener(eventName: 'loadFailed', listenerFunc: (event: AdErrorEvent) => void) => Promise<PluginListenerHandle>Loading failed, for example 509 (no fill). Retry later with a backoff.
| Param | Type |
| ------------------ | ------------------------------------------------------------------------- |
| eventName | 'loadFailed' |
| listenerFunc | (event: AdErrorEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.1.0
addListener('displayed', ...)
addListener(eventName: 'displayed', listenerFunc: (event: AdEvent) => void) => Promise<PluginListenerHandle>The ad was displayed (impression). adInfo.revenue is available here.
| Param | Type |
| ------------------ | --------------------------------------------------------------- |
| eventName | 'displayed' |
| listenerFunc | (event: AdEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.1.0
addListener('displayFailed', ...)
addListener(eventName: 'displayFailed', listenerFunc: (event: AdErrorEvent) => void) => Promise<PluginListenerHandle>The ad failed to display. The pending show call resolves with the same error.
| Param | Type |
| ------------------ | ------------------------------------------------------------------------- |
| eventName | 'displayFailed' |
| listenerFunc | (event: AdErrorEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.1.0
addListener('clicked', ...)
addListener(eventName: 'clicked', listenerFunc: (event: AdEvent) => void) => Promise<PluginListenerHandle>The user clicked the ad.
| Param | Type |
| ------------------ | --------------------------------------------------------------- |
| eventName | 'clicked' |
| listenerFunc | (event: AdEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.1.0
addListener('closed', ...)
addListener(eventName: 'closed', listenerFunc: (event: AdEvent) => void) => Promise<PluginListenerHandle>The ad was closed and the app is back in front.
| Param | Type |
| ------------------ | --------------------------------------------------------------- |
| eventName | 'closed' |
| listenerFunc | (event: AdEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.1.0
addListener('rewarded', ...)
addListener(eventName: 'rewarded', listenerFunc: (event: AdRewardEvent) => void) => Promise<PluginListenerHandle>Rewarded only: the user earned the reward. Can fire before or after closed.
| Param | Type |
| ------------------ | --------------------------------------------------------------------------- |
| eventName | 'rewarded' |
| listenerFunc | (event: AdRewardEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.1.0
addListener('adInfoChanged', ...)
addListener(eventName: 'adInfoChanged', listenerFunc: (event: AdEvent) => void) => Promise<PluginListenerHandle>Rewarded and interstitial: the SDK reloaded the ad in the background and its ad info (network, revenue ...)
changed (onAdInfoChanged / didChangeAdInfo:). Banners and native ads have no such callback in SDK 9.6.1.
| Param | Type |
| ------------------ | --------------------------------------------------------------- |
| eventName | 'adInfoChanged' |
| listenerFunc | (event: AdEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.3.0
addListener('impressionData', ...)
addListener(eventName: 'impressionData', listenerFunc: (event: ImpressionData) => void) => Promise<PluginListenerHandle>Impression-level revenue data for every rewarded, interstitial and banner impression (per-ad
setImpressionDataListener / setImpressionDataDelegate:, attached by the plugin to every ad object it creates),
plus native ad impressions synthesised from the native ad info (adFormat: 'nativead', adInfo fields only).
Add the listener at any time, also before initialize(); nothing is delivered before the first ad shows.
| Param | Type |
| ------------------ | ----------------------------------------------------------------------------- |
| eventName | 'impressionData' |
| listenerFunc | (event: ImpressionData) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.3.0
addListener('bannerLoaded', ...)
addListener(eventName: 'bannerLoaded', listenerFunc: (event: BannerEvent) => void) => Promise<PluginListenerHandle>A banner loaded or refreshed with a new creative.
| Param | Type |
| ------------------ | ----------------------------------------------------------------------- |
| eventName | 'bannerLoaded' |
| listenerFunc | (event: BannerEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.3.0
addListener('bannerLoadFailed', ...)
addListener(eventName: 'bannerLoadFailed', listenerFunc: (event: BannerErrorEvent) => void) => Promise<PluginListenerHandle>A banner load (or refresh) failed. The SDK keeps retrying on its refresh interval.
| Param | Type |
| ------------------ | --------------------------------------------------------------------------------- |
| eventName | 'bannerLoadFailed' |
| listenerFunc | (event: BannerErrorEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.3.0
addListener('bannerDisplayed', ...)
addListener(eventName: 'bannerDisplayed', listenerFunc: (event: BannerEvent) => void) => Promise<PluginListenerHandle>A banner creative was displayed on screen (impression).
| Param | Type |
| ------------------ | ----------------------------------------------------------------------- |
| eventName | 'bannerDisplayed' |
| listenerFunc | (event: BannerEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.3.0
addListener('bannerDisplayFailed', ...)
addListener(eventName: 'bannerDisplayFailed', listenerFunc: (event: BannerErrorEvent) => void) => Promise<PluginListenerHandle>A banner creative failed to display.
| Param | Type |
| ------------------ | --------------------------------------------------------------------------------- |
| eventName | 'bannerDisplayFailed' |
| listenerFunc | (event: BannerErrorEvent) => void |
Returns: Promise<PluginListenerHandle>
Since: 0.3.0
