Floxis Maven/Documentation

Floxis SDK privacy and consent guide#

This guide explains what the Floxis in-app SDKs read from your app, what they send with each auction, and what the exchange removes before any buyer sees a request. It also gives the answers you need for the Google Play Data safety form and the Apple App Store privacy labels.

It covers every Floxis SDK:

SDKArtifactAvailability
Android, AdMobtech.floxis:floxis-sdkReleased (0.2.0)
Android, Google Next-Gen Mobile Adstech.floxis:floxis-sdk-nextgenReleased (0.2.0)
Android, Google Ad Managertech.floxis:floxis-sdk-gamAvailable from the next release; contact your Floxis account manager for early access
Android, AppLovin MAXtech.floxis:floxis-sdk-maxAvailable from the next release; contact your Floxis account manager for early access
Android, Unity LevelPlaytech.floxis:floxis-sdk-levelplayAvailable from the next release; contact your Floxis account manager for early access
iOS, AdMobSwift package FloxisSDKAvailable from the next release; contact your Floxis account manager for early access

Device and session signals (section 6) are added from the next release. Version 0.2.0 does not send them.

You are responsible for your app's consent flow, privacy policy and store disclosures. The SDK never shows a consent screen, never asks for a permission and never shows the App Tracking Transparency prompt. It reads the choices your app and your consent management platform (CMP) have already recorded, and acts on them.

If your app has users in the EEA, the UK or Switzerland, use a CMP that implements IAB TCF v2 (for example Google's User Messaging Platform). For US state privacy laws, use one that also writes the IAB US Privacy string or an IAB GPP string.

The CMP must write the standard IAB keys to the place every ad SDK reads them:

  • Android: the app's default SharedPreferences (the file <your package name>_preferences).
  • iOS: UserDefaults.standard.

Show the consent screen and let the CMP save the result before you load the first ad. The SDK reads the keys again for every auction, so a consent change applies from the next ad load. You do not restart anything.

The SDK does not read Google's Additional Consent string (IABTCF_AddtlConsent).

2. What the SDK reads and where it goes#

The auction request is built by the open-source Prebid Mobile SDK (3.4.0), which Floxis runs inside your app. Prebid Mobile reads the IAB keys and forwards them to the exchange as they are. Floxis also reads some of them for its own checks (sections 3 to 7).

KeyWritten bySent in the auction request asAlso read by Floxis for
IABTCF_gdprAppliesYour CMPregs.ext.gdprDevice signals, location
IABTCF_TCStringYour CMPuser.ext.consentDevice signals
IABTCF_PurposeConsentsYour CMPNot sent; Prebid Mobile uses it to decide whether to send the advertising IDDevice signals (Purpose 1)
IABTCF_SpecialFeaturesOptInsYour CMPNot sentLocation (special feature 1)
IABUSPrivacy_StringYour CMPregs.ext.us_privacyDevice signals, location
IABGPP_HDR_GppStringYour CMPregs.gppDevice signals, location
IABGPP_GppSIDYour CMPregs.gpp_sidDevice signals, location
Child-directed (COPPA) flagYour app (section 4)regs.coppaLocation

The SDK does not validate or rewrite the IAB strings. If a key is missing, it is left out of the request. What the exchange does with them is in section 8.

3. The personalised-ads switch#

Each SDK has one switch for "this user has not agreed to personalised ads". Use it when your consent flow or your own settings screen says so, and update it whenever the choice changes.

SDKSwitchWhat happens when it is off
AdMob, Next-Gen, Google Ad Manager (Android)personalizedAds = false in FloxisConfig, or Floxis.setPersonalizedAds(false)No Floxis auction runs (SKIPPED_NO_CONSENT). The SDK adds npa=1 to its own Google ad request, so Google serves non-personalised ads.
AppLovin MAX (Android)Same as aboveNo Floxis auction runs. MAX loads without Floxis.
iOSpersonalizedAds: false in FloxisConfiguration, or Floxis.shared.setPersonalizedAds(false)No Floxis auction runs. The SDK adds npa=1 to the extras of its own Request and keeps your other extras. It never changes your app-wide Google Mobile Ads settings.
Unity LevelPlayLevelPlay.setConsent(false) or LevelPlayPrivacySettings.setGDPRConsent(false)No Floxis auction runs. The adapter returns no fill with the message "Advertising restricted by privacy signals".

On Android, npa=1 goes into the AdMobAdapter extras bundle (classic and Google Ad Manager) or the Google extras bundle (Next-Gen). While personalised ads are off, it replaces any bundle of that kind you set in your own FloxisRequestFactory (AdMob), requestConfiguration (Google Ad Manager) or FloxisNextGenRequestCustomizer (Next-Gen).

// Android: whenever your consent flow reports a choice
Floxis.setPersonalizedAds(consentAllowsPersonalisedAds)
// iOS
Floxis.shared.setPersonalizedAds(consentAllowsPersonalisedAds)

4. Children and COPPA#

Floxis does not block child-directed traffic. When your app marks a request as child-directed, the SDK passes the flag to the auction as regs.coppa = 1, the way Prebid Mobile and other ad SDKs do. The SDK sends no device location with a child-directed request (section 7), and the exchange removes identifiers and reduces location before any buyer sees it (section 8). Whether your app may show ads to children at all is your decision, under the laws and store policies that apply to it.

How you set the flag depends on the SDK:

SDKHow to mark requests as child-directed
AdMob, Next-Gen, Google Ad Manager (Android)Set Google's app-wide child-directed tag, as you already do for Google. Before every auction the SDK copies it into Prebid Mobile's COPPA flag. If the tag is unspecified, the SDK keeps whatever you set with TargetingParams.setSubjectToCOPPA().
AppLovin MAX (Android)Call TargetingParams.setSubjectToCOPPA(true) yourself. The MAX SDK's own settings do not reach the Floxis auction.
Unity LevelPlayCall TargetingParams.setSubjectToCOPPA(true) yourself. LevelPlayPrivacySettings.setCOPPA and the is_child_directed metadata are never passed to custom networks.
iOSSet Google's app-wide child-directed setting, as you already do for Google. Before every auction the SDK copies it into Prebid Mobile's COPPA flag. If it is unspecified, the SDK keeps whatever you set with Targeting.shared.subjectToCOPPA.

Google Mobile Ads (AdMob classic and Google Ad Manager):

import com.google.android.gms.ads.MobileAds
import com.google.android.gms.ads.RequestConfiguration

MobileAds.setRequestConfiguration(
    MobileAds.getRequestConfiguration().toBuilder()
        .setTagForChildDirectedTreatment(RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE)
        .build(),
)

Google Next-Gen Mobile Ads (add the tag to the request configuration you already build):

import com.google.android.libraries.ads.mobile.sdk.MobileAds
import com.google.android.libraries.ads.mobile.sdk.common.RequestConfiguration

MobileAds.setRequestConfiguration(
    RequestConfiguration.Builder()
        .setTagForChildDirectedTreatment(RequestConfiguration.TagForChildDirectedTreatment.TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE)
        .build(),
)

AppLovin MAX and Unity LevelPlay (import org.prebid.mobile.TargetingParams):

TargetingParams.setSubjectToCOPPA(true)

Prebid Mobile ignores this call until it has initialised:

  • MAX: make the call in the Floxis.initialize callback, once the status is SUCCEEDED or SERVER_STATUS_WARNING.
  • LevelPlay: LevelPlay starts Prebid Mobile when it initialises the Floxis adapter. Make the call after LevelPlay reports that initialisation succeeded, and again before each ad load; repeating it is safe. The LevelPlay adapter puts Prebid Mobile on your app's compile classpath, so you do not add it yourself.

In a debug build, check that TargetingParams.isSubjectToCOPPA() returns true before the first load.

iOS, with Google Mobile Ads' child-directed setting (the SDK reads ageRestrictedTreatment = .child, or the older tagForChildDirectedTreatment as true or false):

import GoogleMobileAds

MobileAds.shared.requestConfiguration.ageRestrictedTreatment = .child

If you leave Google's setting unspecified, set Prebid Mobile's flag yourself:

import PrebidMobile

Targeting.shared.subjectToCOPPA = true

Google Play Families policy#

Floxis is not part of Google Play's Families Self-Certified Ads SDK Program. Under Google Play's Families policy, an app whose target audience is only children may use only self-certified ad SDKs, and an app whose audience includes both children and older users must make sure that ads shown to children come only from self-certified ad SDKs. Read that policy before you serve Floxis demand in such an app.

If your app must not send the Android advertising ID, remove the AD_ID permission that your ad SDKs (for example Google Mobile Ads) merge into your manifest. Floxis itself declares only INTERNET and ACCESS_NETWORK_STATE.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove" />
</manifest>

App Store Kids category#

Apps in the App Store Kids category have their own rules for third-party advertising (App Review Guidelines 1.3 and 5.1.4). Check them before you add any ad SDK to such an app.

5. Advertising ID, IDFA and limited ad tracking#

On both platforms Prebid Mobile reads the advertising ID only when the CMP has recorded consent to storing and accessing information on the device (TCF Purpose 1), or when no Purpose 1 choice is recorded and GDPR does not apply. If Purpose 1 is recorded as refused, the ID is never read, whether or not GDPR applies.

Android. Prebid Mobile reads the advertising ID from Google Play services and, under the rule above, sends it as device.ifa. When the user has opted out of ads personalisation in Android settings, it sends device.lmt = 1.

iOS. The SDK never shows the App Tracking Transparency prompt. If you want buyers to receive the IDFA, add NSUserTrackingUsageDescription to your Info.plist and call ATTrackingManager.requestTrackingAuthorization before you load ads. Prebid Mobile then sends:

  • device.ifa: the IDFA, when the Purpose 1 rule above allows it (it is all zeros unless tracking is authorised);
  • device.ext.ifv: the identifier for vendor, when there is no usable IDFA;
  • device.ext.atts: the App Tracking Transparency status;
  • device.lmt: 0 only when tracking is authorised, 1 otherwise.

The exchange treats any request with device.lmt = 1, or with an App Tracking Transparency status of not determined, restricted or denied, as limited-tracking (section 8). On iOS that is every request from a user who has not authorised tracking.

6. Device and session signals#

From the next release, the SDK can add these signals to an auction. Buyers use them to choose and price ads.

SignalBuyers receive it asAndroid (AdMob, Next-Gen, Google Ad Manager, MAX)Unity LevelPlayiOS
Dark mode on or offdevice.ext.darkmodeYesYesYes
Battery level (0–100)device.ext.batterylevelYesYesOnly if your app has turned on UIDevice.current.isBatteryMonitoringEnabled
Chargingdevice.ext.chargingYesYesOnly if battery monitoring is on
Battery saver / Low Power Modedevice.ext.batterysaverYesYesYes
Ringer silenced or on vibratedevice.ext.ringmuteYesYesNo
Media volume muted or notvideo.playbackmethod on video adsVideo interstitial and rewardedRewardedVideo interstitial and rewarded
Floxis auctions so far this sessionuser.ext.impdepthYesYesYes
Seconds since the session starteduser.ext.sessiondurationYesYesYes

None of these signals is an identifier. video.playbackmethod is 2 when the media volume is at zero and 1 otherwise.

How the device fields travel. iOS sends the five device fields in device.ext. Prebid Mobile on Android drops device.ext from what an app hands it, so the Android SDKs send the same fields in user.ext.floxis.device. The exchange moves them into device.ext before buyers see the request, so buyers receive the same fields from both platforms. If you inspect an Android auction request on the device, look for them under user.ext.floxis.device.

Sessions. On both platforms, impdepth counts only the auctions that carried these signals.

  • Android (every Floxis artifact, LevelPlay included): the session starts with its first auction that carries the signals, and sessionduration counts from there. More than 30 minutes without such an auction starts a new session, and impdepth counts from 1 again. All Floxis artifacts in one app share one session.
  • iOS: the session lasts as long as the app's process. sessionduration counts from the first time the app uses the SDK, and there is no idle reset.

When they are sent (Android AdMob, Next-Gen, Google Ad Manager, MAX, and iOS). All four must be true:

  1. Personalised ads are on (section 3).
  2. GDPR does not apply, or the TCF string is present and grants Purpose 1.
  3. The US Privacy string does not record an opt-out of sale (its third character is not Y).
  4. No applicable GPP US section (national, a state section, or the US Privacy section) in IABGPP_HDR_GppString and IABGPP_GppSID records an opt-out of sale, sharing or targeted advertising.

If any of them fails, every signal in the table is left out, video.playbackmethod included, and the auction still runs without them. The standard device fields (operating system, model, screen size, connection type) are sent either way.

When they are sent (Unity LevelPlay). The adapter runs no auction at all unless all four are true, and sends the signals on every auction it runs:

  1. LevelPlay consent has not been refused (section 3).
  2. GDPR does not apply, or the TCF string is present and grants Purpose 1.
  3. The US Privacy string does not record an opt-out of sale.
  4. No applicable GPP US section (national, a state section, or the US Privacy section) records an opt-out of sale, sharing or targeted advertising.

The child-directed flag does not change whether signals are sent. On a child-directed request the exchange still removes identifiers and reduces location (section 8). On a limited-tracking or US opt-out request, the exchange removes these signals before buyers see it (section 8).

7. Location#

The SDK never asks for a location permission. When your app already holds one, Prebid Mobile can send the device's last known location as device.geo.

SDKLocation is sent only when
Android (AdMob, Next-Gen, Google Ad Manager, MAX)shareLocation is true (the default), the request is not child-directed, GDPR does not apply or TCF special feature 1 ("use precise geolocation data") is opted in, and neither the US Privacy string nor an applicable GPP US section records an opt-out.
iOSshareLocation is true (the default), the request is not child-directed, GDPR does not apply or TCF special feature 1 is opted in, and neither the US Privacy string nor an applicable GPP US section records an opt-out.
Unity LevelPlayNever. The adapter always turns location sharing off.

Android 0.2.0 does not read the GPP keys for location; the GPP condition applies from the next release.

To never send device location, turn it off when you initialise:

FloxisConfig(seat = "YOUR_SEAT", region = "us-e", shareLocation = false)
try FloxisConfiguration(seat: "YOUR_SEAT", region: "us-e", shareLocation: false)

Even without device location, the exchange derives an approximate location (country, region, city and postal code) from the request's IP address.

8. What the exchange removes before buyers see a request#

The SDK sends every auction over HTTPS. The exchange checks each request for limited-tracking and child-directed signals before it forwards it to any buyer.

Limited tracking and US opt-out. A request is treated as limited-tracking when any of these is true:

  • device.lmt = 1;
  • an applicable GPP US section records an explicit opt-out (the section is chosen from the GPP section list and the user's US state);
  • no GPP US section applies, and the US Privacy string records an opt-out of sale;
  • the iOS App Tracking Transparency status is not determined, restricted or denied.

For these requests the exchange:

  • removes the advertising ID, the advertising ID type (device.ext.ifa_type), the iOS identifier for vendor and every hashed device ID;
  • shortens the IP address: the last part of an IPv4 address is zeroed, and an IPv6 address keeps only its first 64 bits. Any other copy of the full IP address in the request is removed;
  • rounds latitude and longitude to two decimal places;
  • removes the user ID, buyer user IDs, year of birth, gender, and every extended user ID in user.eids or user.ext;
  • removes the device and session signals (section 6).

Child-directed requests (regs.coppa = 1). The auction still runs. The exchange removes the same device IDs and shortens the IP address the same way. It reduces location to the country, and removes the user ID, buyer user IDs, year of birth, gender, keywords, user location and user data.

The consent signals travel with the request, so each buyer can apply its own rules too:

  • regs.coppa, the GDPR flag and the GPP string (regs.gpp, regs.gpp_sid) are forwarded;
  • the TCF string (user.ext.consent) is forwarded when GDPR applies;
  • the US Privacy string is forwarded unless the GPP string carries a US section, which then replaces it. On a child-directed request with no US Privacy string, the exchange adds 1NNN.

9. Google Play Data safety form#

Google Play asks you to declare the data that SDKs in your app collect. This table covers what the Floxis Android SDKs (including the LevelPlay adapter) send to the Floxis exchange and its buyers. Declare your ad server or mediation SDK's own data separately, from that provider's disclosure.

Play data typeSent whenCollectedSharedPurpose
Location: Approximate locationEvery request: the exchange derives it from the IP address. Also device location when the app holds only ACCESS_COARSE_LOCATION (section 7).YesYesAdvertising or marketing
Location: Precise locationThe app holds ACCESS_FINE_LOCATION and section 7 allows it. Never with LevelPlay.YesYesAdvertising or marketing
Device or other IDsThe advertising ID is available and section 5 allows itYesYesAdvertising or marketing
App activity: App interactionsSession signals (impdepth, sessionduration), when section 6 allows themYesYesAdvertising or marketing
App info and performance: DiagnosticsDevice signals (battery, charging, battery saver, dark mode, ringer, media volume), when section 6 allows themYesYesAdvertising or marketing

For the other questions on the form:

  • Encrypted in transit: yes. The SDK sends every auction over HTTPS.
  • Required or optional: most apps declare it as required, because ads cannot be served without the request.
  • Processed ephemerally: no. The request is passed on to buyers, so it is not only held in memory for the one request.
  • Deletion requests: answer for your app. Ask your account manager if you need Floxis's data-retention terms.

The request also carries technical fields that are not personal data on their own: device make and model, operating system and version, screen size, language, carrier and connection type, user agent, and your app's package name, version and store URL.

Keep the form current. Check this guide each time you update the SDK.

10. Apple App Store privacy labels#

These labels match the privacy manifest that ships inside the iOS SDK (section 11). Every type is collected for Third-Party Advertising and is linked to the user.

App Store data typeSent whenLinked to the userUsed for tracking
Identifiers: Device IDThe IDFA when tracking is authorised; the identifier for vendor otherwise (section 5)YesYes
Location: Precise LocationThe app holds location permission and section 7 allows itYesYes
Location: Coarse LocationEvery request: the exchange derives it from the IP addressYesNo
Usage Data: Advertising DataEvery auction (the ad requested and the ad shown)YesNo
Usage Data: Product InteractionSession signals, when section 6 allows themYesNo
Other Data: Other Data TypesDevice signals (dark mode, battery, charging, Low Power Mode, media volume muted), when section 6 allows themYesNo

Add the labels from your ad server SDK's own disclosure as well.

11. iOS privacy manifest#

The FloxisSDK Swift package target includes PrivacyInfo.xcprivacy in its resources, so Xcode adds it to your app's privacy report. You do not copy it into your app.

KeyValue
NSPrivacyTrackingtrue
NSPrivacyTrackingDomainsNone
NSPrivacyAccessedAPITypesNSPrivacyAccessedAPICategoryUserDefaults, reason CA92.1 (the SDK reads the consent keys your CMP stored in UserDefaults)
NSPrivacyCollectedDataTypesDevice ID, Precise Location, Coarse Location, Advertising Data, Product Interaction and Other Data Types, all for Third-Party Advertising and linked; Device ID and Precise Location marked as used for tracking

NSPrivacyTracking is true because the SDK can pass the IDFA to buyers, which Apple counts as tracking. It agrees with the two data types marked as used for tracking. What it means for your app:

  • Prebid Mobile reads the IDFA only after the user authorises tracking in the App Tracking Transparency prompt (section 5). If your app never shows the prompt, buyers never receive the IDFA from the SDK.
  • Your App Store privacy answers should include the data used for tracking from section 10.
  • The manifest lists no tracking domains. iOS blocks connections to a listed tracking domain until the user authorises tracking, and the Floxis auction also serves users who have not, so it is not listed. Auctions run whatever the user answers.

A separate hostname for tracking traffic is planned. When it is in place, the manifest will list it and the release notes will say so.

Prebid Mobile 3.4.0 has no privacy manifest of its own beyond the one in its bundled Open Measurement SDK. Google Mobile Ads ships its own.

12. SKAdNetwork (iOS)#

Floxis has no SKAdNetwork ID of its own. Once you set sourceapp (step 2 below), Prebid Mobile copies the SKAdNetworkItems from your app's Info.plist into every request (imp.ext.skadn.skadnetids), so buyers that use SKAdNetwork can attribute installs. Without sourceapp, it sends no SKAdNetwork data at all.

  1. Add Google's SKAdNetwork IDs, which Google Mobile Ads requires, and the IDs your buyers ask you to add. Each is a lowercase SKAdNetworkIdentifier entry in the SKAdNetworkItems array.
  2. Give Prebid Mobile your app's numeric App Store ID, so the request carries sourceapp. Without it, Prebid Mobile logs "Info.plist contains SKAdNetwork but sourceapp is nil!" and leaves SKAdNetwork out of the request.
import PrebidMobile

Targeting.shared.sourceapp = "123456789"

13. Checklist before release#

  1. Your CMP shows its screen and saves the result before the first ad load.
  2. Your app updates the personalised-ads switch whenever consent changes (section 3).
  3. If your app is child-directed, the COPPA flag is set the way your SDK needs (section 4).
  4. On iOS, the App Tracking Transparency prompt, if you show it, is answered before ads load.
  5. On iOS, SKAdNetworkItems and Targeting.shared.sourceapp are set (section 12).
  6. Your Google Play Data safety form and App Store privacy labels include the rows above.
  7. Your privacy policy names your advertising partners and explains how users reset or limit their advertising ID.

14. Troubleshooting#

What you seeWhyWhat to do
Android auction status SKIPPED_NO_CONSENT, or iOS .skippedNoConsentPersonalised ads are off (section 3)Expected for that user. Your ad server still loads; on Google the SDK adds npa=1.
LevelPlay no fill with "Advertising restricted by privacy signals"LevelPlay consent was refused, or a TCF, US Privacy or GPP rule failed (section 6)Check the consent values your CMP stored.
TargetingParams.isSubjectToCOPPA() returns null or false after you set itPrebid Mobile had not initialised yet, so the call was ignoredSet the flag again after initialisation (section 4).
iOS log "Info.plist contains SKAdNetwork but sourceapp is nil!"Targeting.shared.sourceapp is not setSet it to your numeric App Store ID (section 12).
Device and session signals missing from an auction request you capturedA rule in section 6 failed, or, on Android, you looked in device.extExpected when a rule fails. Android sends the device fields in user.ext.floxis.device (section 6).
No device location in the requestThe app has no location permission, shareLocation is off, or a rule in section 7 failedExpected unless all the conditions in section 7 hold.

Setup for each SDK is in In-app SDK (Android), In-app SDK (iOS, AdMob), In-app SDK (Google Ad Manager), In-app SDK (AppLovin MAX) and In-app SDK (Unity LevelPlay). Log codes and test steps are in **SDK testing and troubleshooting, and changes per version in **SDK release notes.