Ethnio Android SDK
Preview: The Ethnio Android SDK is a preview. It is not ready for production apps yet. The SDK will be available soon. Until then, use the WebView implementation in App intercepts implementation using WebView or WKWebView.
What the Android SDK does
An app intercept shows a study as a card inside your Android app. The participant answers the study in the card and does not leave your app. For the basic idea, read The basic idea of app intercepts (iOS, Android).
The Ethnio SDK is a native library that your developer adds to the app one time. The SDK asks Ethnio if the card can show, loads the study and shows the card. It also counts the views and opens the preview links.
Your app decides when the card can show. Ethnio decides if the card shows. The card shows only when all of these conditions are true:
- The study is turned on.
- The targeting rules of the study match.
- The sampling picks the phone.
- The show-once cookie does not stop the card.
- The request does not look like a robot's request.
Quick start
- Copy the code and the SDK key from the Publish page. Read Find the code and the SDK key on the Publish page.
- Add the SDK and its libraries to your app module. Read Install the SDK.
- Initialize the SDK and set the SDK key in
Application.onCreate. Read Initialize the SDK and set the SDK key. - Register the app intercept and show the card. Read Register the app intercept and show the card.
- Add the URL scheme of your app for the QR code preview. Read Preview a study in your app with a QR code.
- Do a test with a test study that is turned on. Read Check the installation.
- Release a new version of your app. Read Release the app.
Before you start
What the researcher needs
- App intercepts need the Enterprise plan.
- The study must use the Beta Editor. A study in the legacy editor cannot use the SDK.
- The developer of your app must add the SDK and release a new version of the app.
What the developer needs
- Android 7.0 (API 24) or later. The SDK needs API 24, so an app with a
minSdkbelow 24 cannot use it. - The app must compile with
compileSdk36 or later. - Kotlin 2.3 or later for a Kotlin app. You can also call the SDK from Java.
- A WebView with the message listener. The Android System WebView has it from version 86.
Find the code and the SDK key on the Publish page
The SDK key is the key of your organization. Every study of your organization uses the same key. Each request of the SDK needs it.
- Open the study in Ethnio.
- Go to the Publish page.
- Find the section "App intercept".
- Under "How your app shows the intercept", select "Android SDK".
- Click "Copy" to copy the code for this study.
- Click "Copy key" to copy only the SDK key.
The code on the Publish page has the id of the study and the SDK key of your organization. Give the code or the key to your developer.
Install the SDK
Ethnio does not publish the SDK to Maven Central yet. When the SDK is available, Ethnio gives you the file ethnio-sdk-<version>.aar .
- Copy
ethnio-sdk-<version>.aarinto the folderlibsof your app module. - Add the AAR file to the
dependenciesof your app module. - Add the libraries of the SDK to the same
dependencies. An AAR file does not bring its libraries.
dependencies {
implementation(files("libs/ethnio-sdk-1.1.0.aar"))
implementation("androidx.core:core-ktx:1.18.0")
implementation("androidx.webkit:webkit:1.18.0")
implementation("androidx.activity:activity:1.13.0")
implementation("androidx.browser:browser:1.10.0")
implementation("androidx.lifecycle:lifecycle-process:2.9.4")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0")
}
Initialize the SDK and set the SDK key
- Call
Ethnio.initialize(context)one time inApplication.onCreate, before the first call to the SDK. - If your app has no
Applicationclass, add one. - Name the class in
android:nameof the<application>element in the manifest. - Set
Ethnio.sdkKeyone time, before the first call to the SDK.
Main thread: Call the SDK on the main thread. The calls of the SDK have the annotation @MainThread . The suspend functions registerIntercept and clearCookie go to the main thread themselves.
import io.ethn.sdk.Ethnio
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// Call initialize once, before the first call.
Ethnio.initialize(this)
// Set your organization's SDK key once, before the first call.
Ethnio.sdkKey = "<key>"
Ethnio.onEvent = { event -> Log.d("MyApp", "$event") }
}
}
Replace <key> with the key from "Copy key". The SDK removes spaces and line breaks at the start and at the end of the key. An empty key counts as no key. A key with a space or a line break inside it also counts as no key.
Before Ethnio.initialize , every call except hide does nothing and writes an error to the log. If the key is not set, the SDK sends no request and shows no card. Every call except hide then does nothing.
Register the app intercept and show the card
The SDK shows the card in two steps:
- Call
registerInterceptto ask Ethnio if the card can show now. - If the answer is yes, call
displayto show the card.
// In an activity, for example in onCreate. The card shows over the resumed activity.
lifecycleScope.launch {
if (Ethnio.registerIntercept(studyId = 1, embeddedData = mapOf("plan" to "pro"))) {
Ethnio.display(studyId = 1)
}
}
// Later, on any screen.
if (Ethnio.isActive(studyId = 1)) Ethnio.display(studyId = 1)
Replace 1 with the id of your study. The code on the Publish page shows the id.
Call the SDK on the main thread. The card shows over the resumed activity of your app. Thus, call display after onResume of the activity.
The calls
| Call | What it does |
|---|---|
Ethnio.initialize(context) |
Starts the SDK. Call it one time in Application.onCreate. The iOS SDK does not have this call. |
Ethnio.registerIntercept(studyId, embeddedData, language, preview) |
Sends the status request to Ethnio. Returns true if the card can show now. The SDK keeps the answer for isActive. If the request fails, the call returns false. It is a suspend function. |
Ethnio.isActive(studyId) |
Gives the last answer of the status request. It sends no request. Before the first answer, it gives false. |
Ethnio.statusReason(studyId) |
Gives the reason for the last "no" answer, such as turned_off. It gives null while the study can show. |
Ethnio.display(studyId) |
Loads the study and shows the card when the page is ready. Returns true when the load starts. Returns false when the card cannot show. A Failed event then gives the reason. |
Ethnio.hide() |
Closes the card, or stops a card that still loads. The app gets a Closed event with the reason APP. |
Ethnio.clearCookie(studyId) |
Removes the show-once cookie of the study from the phone. Use it only for tests. It is a suspend function. After this call, call registerIntercept again. |
Ethnio.handleLink(uri) |
Opens a preview link from the QR code on the Publish page. Returns true for an Ethnio link and false for the other links of your app. |
If your app does not use coroutines, or if it uses Java, use registerIntercept with a completion function. The function runs on the main thread. In Java, the function returns Unit.INSTANCE .
Ethnio.registerIntercept(studyId = 1, embeddedData = mapOf("plan" to "pro")) { active ->
if (active) Ethnio.display(studyId = 1)
}
If you call registerIntercept again for the same study, the new embedded data replaces the old data. The SDK then asks Ethnio again.
Where to call the SDK
The card shows over the resumed activity of your app. Thus, call display while an activity of your app is on screen. If the app has no resumed activity, the Failed event has the reason NoWindow .
Jetpack Compose: Call registerIntercept and display in a LaunchedEffect inside setContent of your ComponentActivity . The effect starts after the first composition. display runs after the answer of Ethnio.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LaunchedEffect(Unit) {
if (Ethnio.registerIntercept(studyId = 1)) {
Ethnio.display(studyId = 1)
}
}
AppContent()
}
}
}
Views: Call registerIntercept in lifecycleScope.launch of the activity, as in the example above.
Ethnio has no React Native or Flutter package. Such an app uses the WebView implementation.
Check the installation
Do this check with a debug build of your app before you release it.
- Set
Ethnio.logLevel = EthnioLogLevel.DEBUGinApplication.onCreate. - Ask the researcher for the id of a test study that is turned on.
- Call
registerInterceptwith the id of the test study. Do not setpreview = true. - In Logcat, filter for the tag
Ethnio. - Find the status line. If the card can show, the line is
status 1: true. - If the answer is no, the line has the status reason in parentheses, for example
status 1: false (turned_off). - If the request failed, the line is
status 1 failed:and the system error. - If the answer is no, read
Ethnio.statusReason(studyId). Find the reason in Status reasons and failure reasons. - If the answer is yes, call
display. - Answer the questions in the card and submit.
- Find the
Submittedevent in Logcat, for exampleevent Submitted(studyId=1, qualified=qualified). - Open the responses page of the study in Ethnio.
- Find the new response. Its referrer is "App Intercept (Android)".
A card from a preview gives a response with the referrer "Preview". If the Cookie setting of the study is on, the card does not show again on this phone. For a new test, call Ethnio.clearCookie(studyId) .
Test without real participants
Use one of these two methods:
- Preview: Open a test study with the QR code preview, or call
registerInterceptwithpreview = true. A preview ignores the turned-off state, the targeting rules, the sampling, the cookie and the robot check. A preview card writes no cookie. - Turned-on test study: Turn on a test study and set its Cookie setting to off. Then the card can show again after each close or submission. The targeting rules and the sampling still apply.
A turned-on study can also show to the people who use your app. Thus, give the test study targeting rules that match only your test phones.
Release the app
The card shows only in the versions of your app that include the SDK. A phone with an older version of your app shows no card.
If your app uses R8 or ProGuard, you do not add rules. The SDK brings its own rules file, and the SDK needs no keep rule.
- Remove the line that sets
Ethnio.logLevel = EthnioLogLevel.DEBUG. - Remove
preview = truefrom your calls. - Release the new version of your app.
- Tell the researcher which version of the app has the SDK.
Embedded data and language
Embedded data
The embeddedData parameter is a map of text keys and text values. Ethnio uses it in two places:
- The targeting rules of the study.
- The embedded data questions of the study.
A value can contain any character, also + and ; . A targeting rule cannot read a key with brackets, such as user[plan] .
Some keys have a special meaning:
email,nameandphonefill the contact questions of the study. If a contact question has "Hide question if prepopulated" on, the participant does not see it.- The SDK does not send
preview,sdk_keyandl. Use the parameterspreviewandlanguageofregisterInterceptinstead. Set the key inEthnio.sdkKey. - The SDK does not send keys that start with
ethnio_. The SDK uses this prefix for its own parameters.
Language
The language parameter sets the language of the study texts. Use a BCP 47 code, such as fr or pt-BR .
What the SDK sends about the app
The SDK adds these parameters to the status request and to the page:
| Parameter | Value |
|---|---|
ethnio_platform |
Always android. |
ethnio_os_version |
The Android version, such as 14. |
ethnio_device |
The manufacturer and the model of the phone, such as Google Pixel 8. |
ethnio_app_version |
The version name of your app. |
ethnio_app_build |
The version code of your app. |
ethnio_sdk_version |
The version of the SDK. |
ethnio_app_sessions |
The number of app sessions on this phone. |
A targeting rule can use these seven names. The rule compares exact values. The response keeps the seven values, unless the Ethnio account has "Disable Metadata" on.
The page also gets the font size of the participant. The card follows the font size of the phone settings up to 200%.
Events
Set Ethnio.onEvent to receive the events of the card. Each event comes on the main thread and has the studyId .
| Event | What it means |
|---|---|
EthnioEvent.Displayed |
The card is on screen. |
EthnioEvent.Submitted |
Ethnio saved the answers of the participant. qualified is "qualified", "disqualified" or "neutral". |
EthnioEvent.Closed |
The card closed. The reason is PARTICIPANT, APP, ENDING or SYSTEM. |
EthnioEvent.Failed |
The card did not show. The reason tells why. See the next section. |
Close reasons
PARTICIPANT: The participant closed the card with the close X, with "No thanks" on the invite or with a tap on the overlay.APP: Your app calledEthnio.hide(), or a preview link closed the card.ENDING: The participant closed the ending page.SYSTEM: The system ended the card. For example, the activity of the card ended while the card was on screen. A rotation ends the activity, unless your app handles the configuration change itself.
If a researcher turns off the study while the card is open, the card shows the ending. In this case, the app gets no Submitted event.
Status reasons and failure reasons
If the answer is no, Ethnio.statusReason(studyId) gives the status reason. If your app then calls display , the Failed event gives the same reason as a case of FailureReason .
| Status reason | Failure case | What it means | What to do |
|---|---|---|---|
turned_off |
TurnedOff |
The study is turned off. | Ask the researcher to turn on the study. |
not_targeted |
NotTargeted |
The targeting rules do not match. | Examine the targeting rules and the embedded data that your app sends. |
outside_of_sample |
OutsideOfSample |
The sampling ("Show to this share of visitors") did not pick this phone. | Nothing. The phone always gets the same answer for this study. |
already_displayed |
AlreadyDisplayed |
The participant closed the card or submitted on this phone in the last 30 days. The Cookie setting of the study is on. | Nothing. For a test, call Ethnio.clearCookie(studyId). |
robot |
Robot |
The request looked like a robot's request. | Nothing. |
legacy_editor |
LegacyEditor |
The study does not use the Beta Editor. | Use a study that uses the Beta Editor. |
not_found |
NotFound |
No study has this id. | Copy the study id from the Publish page. |
wrong_key |
WrongKey |
The SDK key belongs to another organization. | Copy the key with "Copy key" on the Publish page of the study. |
no_sdk_key |
NoSdkKey |
The app set no SDK key. | Set Ethnio.sdkKey before the first call. |
network |
Network |
The status request failed. The case holds the system error in error. |
Examine the error and the network connection. Then call registerIntercept again. |
The Failed event can also have these cases:
| Failure case | What it means | What to do |
|---|---|---|
NotActive |
The study does not show now, and Ethnio gave no reason. For example, the first answer did not arrive yet. | Wait for the result of registerIntercept before you call display. |
NotRegistered |
The app called display for a study id that registerIntercept never got. |
Call registerIntercept for the study first. |
Busy |
Another card is on screen or still loads. | Wait for the Closed event of the other card. |
NoWindow |
The app has no resumed activity, so the SDK cannot show the card. | Call display after onResume of the activity. |
Network |
The status request failed, or the page did not load. The SDK also sends this case if the phone has no WebView, or if the WebView is older than version 86. | Examine the system error in error. Update the Android System WebView on the phone. |
Timeout |
The page did not get ready within 30 seconds. | Examine the network connection. |
Publish page settings that apply to the card
The Options tab of the Publish page has three settings for the app intercept:
- Show to this share of visitors: The part of the matching people in your app who can see the card. The phone keeps one random number for each study. Thus, a person is always in the share or always out of it.
- Delay after the app asks for the card: The SDK waits this long after your app calls
display. If your app callshide()or goes to the background, the SDK cancels the waiting card. - Cookie: If the participant closes the card or submits, the card writes a cookie. Then the card does not show again on this phone for 30 days. A card that only shows writes no cookie. A call to
hide()writes no cookie. For more about the cookie, read How our cookie works.
The "App intercept design" tab of the Design page sets the look of the card. Position puts the card at the Bottom, the Center or the Top of the screen, or uses Full screen. The tab also has Overlay, "Tap outside the card closes it", Card shadow, Card corner radius and the card size.
For now, the card ignores the Back gesture and the Back button. The participant closes the card with the close X or with "No thanks". If "Tap outside the card closes it" is on, a tap outside a regular card also closes it.
A link in the study to another site opens in a Custom Tab above the card. When the participant closes the Custom Tab, the card shows the same page again.
Preview a study in your app with a QR code
A researcher can see a study inside your app before participants see it. The preview also shows a study that is turned off. The preview ignores the targeting rules, the sampling, the cookie and the robot check.
For the researcher
- On the Publish page, go to the section "Preview in your app".
- Enter the URL scheme of your app in "App link scheme". The scheme is the part before
://in the links of your app. - Scan the QR code with your phone.
Each study keeps its own scheme. The QR code holds the link <scheme>://ethnio/preview/<study id> . Your app opens and shows the study in preview. A system scheme such as https does not work. Enter the scheme of your own app.
For the developer
- Add an intent filter for your URL scheme to the activity that opens the links. Use the host
ethnio. - Set
Ethnio.sdkKeybefore your app gives a link to the SDK. - Give each link that your app opens to
Ethnio.handleLink.
With launchMode="singleTop" , a link to the open app goes to onNewIntent , and no second activity starts:
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="ethnio" />
</intent-filter>
</activity>
If the link starts the activity, the link is in the intent of onCreate . If the activity runs, the link arrives in onNewIntent :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// A rotation starts the activity again with the same intent. Only the first start gives the link to the SDK.
if (savedInstanceState == null) intent?.data?.let { Ethnio.handleLink(it) }
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intent.data?.let { Ethnio.handleLink(it) }
}
During development, you can open the link without a QR code:
adb shell am start -a android.intent.action.VIEW -d "myapp://ethnio/preview/1" <your application id>
The SDK key of your app proves your organization. Thus, your app shows only the studies of your organization in preview. Without the key, the SDK ignores the link and writes an error to the log. If the key belongs to another organization, the Failed event has the reason WrongKey .
A preview card sends the same events as the card of a participant. Do not reward or count a submission while you test.
To preview a study from your own code, call registerIntercept with preview = true . Use it only to test the study.
Camera and microphone questions
If the study records video or has a tech check, add these permissions to the manifest of your app:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.microphone" android:required="false" />
- Without
MODIFY_AUDIO_SETTINGS, the WebView records no sound. - Without the two
uses-featurelines, Google Play does not show your app on a device without a camera or a microphone. - The SDK never asks for a permission. Your app must ask the participant for
CAMERAandRECORD_AUDIO. - For the image upload question, the activity of the card must be a
ComponentActivity, for example anAppCompatActivity.
Settings
Ethnio.sdkKey: The SDK key of your organization.Ethnio.logLevel: The SDK messages in Logcat, with the tagEthnio:NONE,ERRORSorDEBUG. The default isERRORS. WithDEBUG, you can also inspect the page of the card inchrome://inspect.Ethnio.baseURL: The default ishttps://ethn.io. Do not change it.
Troubleshooting
The card never shows
- Make sure that
Ethnio.initializeruns inApplication.onCreate. - Set
Ethnio.logLevel = EthnioLogLevel.DEBUGand read Logcat with the tagEthnio. - Read
Ethnio.statusReason(studyId)afterregisterIntercept. - Find the reason in the table of status reasons above.
The Failed event has the reason Network , but the network works
The phone can have no WebView, or a WebView older than version 86. Update the Android System WebView on the phone.
The Failed event has the reason NoWindow
The app called display while the app had no resumed activity. Call display after onResume , for example from the result of registerIntercept .
The card showed one time and then never again
If the Cookie setting is on, the card does not show again for 30 days after a close or a submission. For a test, call Ethnio.clearCookie(studyId) . Then call registerIntercept again.
The card closes when the participant turns the phone
A rotation ends the activity and starts it again. The card then closes with the reason SYSTEM . To keep the card, let your app handle the configuration change itself.
The QR code does not open the app
- The "App link scheme" on the Publish page can be wrong. Enter the URL scheme of your app, without
://. - The app can be without an intent filter for the scheme. Add the intent filter with your scheme and the host
ethnioto the activity. Setandroid:exported="true"on the activity.
The app opens, but no card shows
- The link does not get to
handleLink. Give the link ofonCreateand ofonNewIntenttoEthnio.handleLink. - The app calls
handleLinkbefore it sets the SDK key. The SDK then ignores the link. Logcat showsEthnio.sdkKey is not present (handleLink). Set the key before the first call.SetEthnio.sdkKeyinApplication.onCreate. - The app calls
handleLinkbeforeEthnio.initialize. Logcat showsCall Ethnio.initialize(context) in Application.onCreate before the first call. - The SDK key belongs to another organization. The
Failedevent then has the reasonWrongKey. Copy the key with "Copy key" on the Publish page.
The test phone has an older build of the app
A build without the SDK shows no card and no preview. Install a build that includes the SDK and the intent filter on the test phone.
The tech check shows "Could not start devices"
The camera and the microphone work only on an https page. Use the default server address of the SDK.
Your app does not use the SDK
Your app can show the study in its own WebView. Read App intercepts implementation using WebView or WKWebView.