Skip to content

Testing & debugging

When a survey does not appear, the SDK always knows why. Two places tell you: the debug log and the surveyNotShown callback.

Set the log level to debug when you initialize the SDK.

Responsly.shared.initialize(sdkKey: "rsk_…", options: ResponslyOptions(logLevel: .debug))

Every line starts with [Responsly]. At the debug level the SDK logs:

  • every targeting decision, with the Survey ID and the reason when a survey is not shown,
  • every configuration download and its result,
  • every step in the life of a survey: loading, shown, answered, completed, closed.
LevelLogs
noneNothing.
errorProblems that need your attention, such as an invalid SDK key.
infoErrors, plus notable events such as initialization and failed downloads.
debugEverything above, plus every decision.

Where to read it:

AppWhere
iOSXcode console, or Console.app with the filter [Responsly]
AndroidLogcat with the filter Responsly
React Native, FlutterThe same native logs: Xcode console for iOS, Logcat for Android
Unity on a deviceThe same native logs: Xcode console for iOS, adb logcat for Android
Unity EditorThe Unity Console. In the Editor every call is a no-op that only logs.

Use debug in development builds and error or none in release builds. The installation pages show how to switch on the build type.

On iOS, the debug level also makes the survey inspectable with Safari’s Web Inspector.

In development builds it helps to surface the reason on screen or in your own log.

final class NotShownLogger: ResponslyListener {
func surveyNotShown(_ event: ResponslySurveyNotShownEvent) {
print("Survey \(event.surveyId) not shown: \(event.reason.rawValue)")
}
}
let notShownToken = Responsly.shared.addListener(NotShownLogger())

The checks run in a fixed order and the first failing one gives the reason. The order is in Targeting.

ReasonWhat it meansHow to fix it
disabledThe SDK is switched off with setTrackingEnabled(false). The setting survives restarts.Call setTrackingEnabled(true).
not_initializedshowSurvey was called before initialize.Call initialize at app start, before any showSurvey.
config_unavailableThe configuration could not be downloaded and there is no cached copy.Check the SDK key (it starts with rsk_ and belongs to the right team) and the network connection. With an invalid key nothing is shown until the app is restarted with a valid one.
survey_not_foundThe Survey ID is not in the configuration.Check the ID. Check that the Mobile app channel is switched on for that form and that the form belongs to the team of the SDK key. If you just switched it on, the device may still hold the old configuration; see Configuration cache.
another_survey_visibleA survey is on screen, or one is waiting for its delay.Expected: one survey at a time. Close the current one, or space the triggers apart.
another_survey_selectedSeveral surveys matched the same trigger and another one was shown.Expected. If the wrong one wins, separate them with audience or frequency rules.
pausedYour code called pause.Call resume, or use showSurvey, which ignores the pause.
outside_scheduleThe current time is before from or at or after until.Adjust the schedule. Check the device clock.
platform_mismatchThe survey is limited to the other platform.Add this platform in the audience settings, or clear the platform list.
app_mismatchThe app ID is not in the survey’s list. The comparison is case-sensitive.Add the app ID. Debug builds often have a different ID, for example with a .debug suffix.
locale_mismatchThe SDK’s language is not in the survey’s languages list.Add the language, clear the list, or check what you pass to setLocale.
audience_mismatchThe identified / not identified rule or the attribute conditions are not met.Check that identify or setAttributes ran before the trigger, that attribute names are spelled the same, and that values have the type the condition expects (number 5, not text "five").
already_completedThis install has completed the survey and the frequency is once or until completed.Expected. To test again, call reset or use force.
frequency_limitThe survey was already shown and the frequency is once, or the maximum number of displays is reached.Expected. Change the frequency, raise the maximum, or call reset while testing.
recontact_waitThe days between displays have not passed yet.Wait, lower the number of days, or call reset while testing.
global_cooldownThe team-wide pause between surveys is still running after another survey.Wait, shorten the pause, or use showSurvey, which ignores it.
sampled_outThis install is outside the share of users.Set the share to 100% while testing. The answer for an install does not change until you raise the share or reinstall.
screen_changedThe survey had a delay and the user left the screen before it ended.Shorten the delay, or trigger on an event instead of a screen.
vetoedYour display guard returned false.Check the guard’s condition.
load_failedThe survey did not load within 15 seconds, or the load failed.Check the connection. A survey needs the network when it is shown. Nothing is counted as a display.
survey_unavailableThe survey loaded but reported that it cannot be answered right now.Open the form’s link in a browser to see what respondents see, and check that the form is accepting responses.

To see a survey regardless of audience, schedule and frequency, call showSurvey with force. It also skips the display guard.

Responsly.shared.showSurvey("AbCd1234", options: ResponslyShowOptions(force: true))

A forced survey can still fail with disabled, not_initialized, config_unavailable, survey_not_found, another_survey_visible, load_failed or survey_unavailable. If it appears, the integration works and the cause is in the targeting rules.

A debug menu entry that forces each of your surveys is a cheap way to let designers and QA review them in the real app.

Targeting state lives on the device, so most surprises come from history left by earlier test runs.

To testDo this
A rule from scratchCall reset. It clears event counts, display history and identity, and downloads the configuration again.
Frequency rulesSet every time while you test other things, then set the real mode and call reset once.
”From occurrence no.”Counts survive restarts. Call reset to start from zero.
Share of usersTest at 100%. An install’s position is fixed; only a reinstall gives a new one.
Audience conditionsCall identify or setAttributes with the test values before the trigger. Watch for audience_mismatch.
The app launch triggerQuit the app completely and start it again. Returning from the background is not a launch.
A delay on a screen triggerStay on the screen for the whole delay. Leaving gives screen_changed.
LanguagesCall setLocale instead of changing the device language. Call setLocale with null afterwards.
The pause between surveysIt applies to triggers only. Show one survey by a trigger, then fire another trigger.

Test displays and test responses are real: they are counted in the Mobile app tab and saved in the form’s results. Delete the test responses afterwards, or test with a copy of the form.

The SDK does not ask the server on every call. It works from a cached copy of the configuration.

  • The cache lives for about 10 minutes.
  • At initialize the SDK loads the cached copy and downloads a new one if there is none or it has expired.
  • When the app returns to the foreground with an expired cache, it downloads again.
  • While the cache is fresh, restarting the app does not download anything.

A change saved in the Mobile app tab therefore reaches a device within about 10 minutes, at the next app start or return to the foreground after the cache expires.

To pick up a change immediately while testing, call reset or reinstall the app. Both drop the cache.

Other cases:

  • Offline with a cache. Targeting still runs, but a survey cannot load and reports load_failed.
  • Offline without a cache (first start). track and screen calls wait in a short queue and are evaluated when the configuration arrives. showSurvey reports config_unavailable.
  • Download failed. The SDK keeps the cached copy and tries again the next time the app comes to the foreground.
  • Invalid SDK key. The SDK drops the cache and shows nothing until the next app start.

The Mobile app tab shows how many times the survey was shown, completed and closed in the last 30 days. The SDK sends these counts in small batches, so the numbers can lag a little behind what you just did on the device. Sending the app to the background flushes them. Nothing is counted while the SDK is switched off with setTrackingEnabled(false).