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:
| SDK | Artifact | Availability |
|---|---|---|
| Android, AdMob | tech.floxis:floxis-sdk | Released (0.2.0) |
| Android, Google Next-Gen Mobile Ads | tech.floxis:floxis-sdk-nextgen | Released (0.2.0) |
| Android, Google Ad Manager | tech.floxis:floxis-sdk-gam | Available from the next release; contact your Floxis account manager for early access |
| Android, AppLovin MAX | tech.floxis:floxis-sdk-max | Available from the next release; contact your Floxis account manager for early access |
| Android, Unity LevelPlay | tech.floxis:floxis-sdk-levelplay | Available from the next release; contact your Floxis account manager for early access |
| iOS, AdMob | Swift package FloxisSDK | Available 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.
1. Use a TCF v2 consent management platform#
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).
| Key | Written by | Sent in the auction request as | Also read by Floxis for |
|---|---|---|---|
IABTCF_gdprApplies | Your CMP | regs.ext.gdpr | Device signals, location |
IABTCF_TCString | Your CMP | user.ext.consent | Device signals |
IABTCF_PurposeConsents | Your CMP | Not sent; Prebid Mobile uses it to decide whether to send the advertising ID | Device signals (Purpose 1) |
IABTCF_SpecialFeaturesOptIns | Your CMP | Not sent | Location (special feature 1) |
IABUSPrivacy_String | Your CMP | regs.ext.us_privacy | Device signals, location |
IABGPP_HDR_GppString | Your CMP | regs.gpp | Device signals, location |
IABGPP_GppSID | Your CMP | regs.gpp_sid | Device signals, location |
| Child-directed (COPPA) flag | Your app (section 4) | regs.coppa | Location |
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.
| SDK | Switch | What 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 above | No Floxis auction runs. MAX loads without Floxis. |
| iOS | personalizedAds: 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 LevelPlay | LevelPlay.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:
| SDK | How 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 LevelPlay | Call TargetingParams.setSubjectToCOPPA(true) yourself. LevelPlayPrivacySettings.setCOPPA and the is_child_directed metadata are never passed to custom networks. |
| iOS | Set 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.initializecallback, once the status isSUCCEEDEDorSERVER_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 = .childIf you leave Google's setting unspecified, set Prebid Mobile's flag yourself:
import PrebidMobile
Targeting.shared.subjectToCOPPA = trueGoogle 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:0only when tracking is authorised,1otherwise.
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.
| Signal | Buyers receive it as | Android (AdMob, Next-Gen, Google Ad Manager, MAX) | Unity LevelPlay | iOS |
|---|---|---|---|---|
| Dark mode on or off | device.ext.darkmode | Yes | Yes | Yes |
| Battery level (0–100) | device.ext.batterylevel | Yes | Yes | Only if your app has turned on UIDevice.current.isBatteryMonitoringEnabled |
| Charging | device.ext.charging | Yes | Yes | Only if battery monitoring is on |
| Battery saver / Low Power Mode | device.ext.batterysaver | Yes | Yes | Yes |
| Ringer silenced or on vibrate | device.ext.ringmute | Yes | Yes | No |
| Media volume muted or not | video.playbackmethod on video ads | Video interstitial and rewarded | Rewarded | Video interstitial and rewarded |
| Floxis auctions so far this session | user.ext.impdepth | Yes | Yes | Yes |
| Seconds since the session started | user.ext.sessionduration | Yes | Yes | Yes |
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
sessiondurationcounts from there. More than 30 minutes without such an auction starts a new session, andimpdepthcounts from 1 again. All Floxis artifacts in one app share one session. - iOS: the session lasts as long as the app's process.
sessiondurationcounts 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:
- Personalised ads are on (section 3).
- GDPR does not apply, or the TCF string is present and grants Purpose 1.
- The US Privacy string does not record an opt-out of sale (its third character is not
Y). - No applicable GPP US section (national, a state section, or the US Privacy section) in
IABGPP_HDR_GppStringandIABGPP_GppSIDrecords 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:
- LevelPlay consent has not been refused (section 3).
- GDPR does not apply, or the TCF string is present and grants Purpose 1.
- The US Privacy string does not record an opt-out of sale.
- 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.
| SDK | Location 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. |
| iOS | shareLocation 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 LevelPlay | Never. 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.eidsoruser.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 type | Sent when | Collected | Shared | Purpose |
|---|---|---|---|---|
| Location: Approximate location | Every request: the exchange derives it from the IP address. Also device location when the app holds only ACCESS_COARSE_LOCATION (section 7). | Yes | Yes | Advertising or marketing |
| Location: Precise location | The app holds ACCESS_FINE_LOCATION and section 7 allows it. Never with LevelPlay. | Yes | Yes | Advertising or marketing |
| Device or other IDs | The advertising ID is available and section 5 allows it | Yes | Yes | Advertising or marketing |
| App activity: App interactions | Session signals (impdepth, sessionduration), when section 6 allows them | Yes | Yes | Advertising or marketing |
| App info and performance: Diagnostics | Device signals (battery, charging, battery saver, dark mode, ringer, media volume), when section 6 allows them | Yes | Yes | Advertising 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 type | Sent when | Linked to the user | Used for tracking |
|---|---|---|---|
| Identifiers: Device ID | The IDFA when tracking is authorised; the identifier for vendor otherwise (section 5) | Yes | Yes |
| Location: Precise Location | The app holds location permission and section 7 allows it | Yes | Yes |
| Location: Coarse Location | Every request: the exchange derives it from the IP address | Yes | No |
| Usage Data: Advertising Data | Every auction (the ad requested and the ad shown) | Yes | No |
| Usage Data: Product Interaction | Session signals, when section 6 allows them | Yes | No |
| Other Data: Other Data Types | Device signals (dark mode, battery, charging, Low Power Mode, media volume muted), when section 6 allows them | Yes | No |
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.
| Key | Value |
|---|---|
NSPrivacyTracking | true |
NSPrivacyTrackingDomains | None |
NSPrivacyAccessedAPITypes | NSPrivacyAccessedAPICategoryUserDefaults, reason CA92.1 (the SDK reads the consent keys your CMP stored in UserDefaults) |
NSPrivacyCollectedDataTypes | Device 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.
- Add Google's SKAdNetwork IDs, which Google Mobile Ads requires, and the IDs your buyers ask you to add. Each
is a lowercase
SKAdNetworkIdentifierentry in theSKAdNetworkItemsarray. - 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#
- Your CMP shows its screen and saves the result before the first ad load.
- Your app updates the personalised-ads switch whenever consent changes (section 3).
- If your app is child-directed, the COPPA flag is set the way your SDK needs (section 4).
- On iOS, the App Tracking Transparency prompt, if you show it, is answered before ads load.
- On iOS,
SKAdNetworkItemsandTargeting.shared.sourceappare set (section 12). - Your Google Play Data safety form and App Store privacy labels include the rows above.
- Your privacy policy names your advertising partners and explains how users reset or limit their advertising ID.
14. Troubleshooting#
| What you see | Why | What to do |
|---|---|---|
Android auction status SKIPPED_NO_CONSENT, or iOS .skippedNoConsent | Personalised 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 it | Prebid Mobile had not initialised yet, so the call was ignored | Set the flag again after initialisation (section 4). |
| iOS log "Info.plist contains SKAdNetwork but sourceapp is nil!" | Targeting.shared.sourceapp is not set | Set it to your numeric App Store ID (section 12). |
| Device and session signals missing from an auction request you captured | A rule in section 6 failed, or, on Android, you looked in device.ext | Expected when a rule fails. Android sends the device fields in user.ext.floxis.device (section 6). |
| No device location in the request | The app has no location permission, shareLocation is off, or a rule in section 7 failed | Expected unless all the conditions in section 7 hold. |
Related guides#
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.