Logging

The Descope mobile SDKs can emit log messages to help you diagnose authentication, session, and flow issues during development.

Logging is disabled by default. No output is produced until you explicitly set a logger on the SDK configuration.

Built-in Loggers

The Swift, Kotlin, and Flutter SDKs each ship three built-in loggers. They differ in how much they print, and in whether they print unsafe runtime values — full network request and response payloads, tokens, secrets, and personal information.

LoggerPrintsUnsafe values
basicLoggerErrors and infoNever
debugLoggerErrors, info and debugOnly when the app is running in a debug context
unsafeLoggerErrors, info and debugAlways

debugLogger is the right choice in most cases. You can add it while diagnosing an issue, and it will not leak sensitive data if you forget to remove it before shipping a build to the App Store or Play Store.

The debug context that debugLogger detects differs between platforms. On Swift it means a debugger is attached to the process, so the app was launched from Xcode. On Kotlin it means the application is marked debuggable, whether or not Android Studio is attached. On Flutter it means the app was compiled in debug mode, so unsafe values are never printed in profile or release builds.

React Native does not use these built-in loggers - see the React Native tab under Enabling a Logger below.

Even with unsafe values off, error logs stay actionable - the Descope error code and API route are part of the message itself. For example, a failed OTP verification on Android prints a log line like this:

[DescopeAndroid] Network call to auth/otp/verify/email failed with E061102 server error

Enabling a Logger

Descope.setup(projectId: "__ProjectID__") { config in
    config.logger = .debugLogger
}
Descope.setup(this, projectId = "__ProjectID__") {
    logger = DescopeLogger.debugLogger
}
Descope.setup('__ProjectID__', (config) {
  config.logger = DescopeLogger.debugLogger;
});

On Flutter, log messages from the underlying native iOS and Android SDKs are forwarded to your logger automatically once one is set, so native flow execution appears alongside your Dart logs.

Your logger's unsafe setting is passed through to the native layer, so unsafeLogger also captures native payloads.

The React Native SDK takes a logger object rather than one of the built-in loggers above. Pass it to AuthProvider:

const logger = {
  log: (message) => console.log(message),
  debug: (message) => console.debug(message),
  warn: (message) => console.warn(message),
  error: (message) => console.error(message),
}

<AuthProvider projectId="__ProjectID__" logger={logger}>
  <App />
</AuthProvider>

During development you can pass console directly, or point the methods at a monitoring service instead.

The bridge forwards log messages from the native iOS and Android SDKs to this logger, so native flow execution shows up alongside your JavaScript logs. That helps when a flow loads but never completes. Native info messages arrive as log.

The bridge always runs with unsafe logging disabled, so it never prints native payloads or tokens. React Native has no equivalent of unsafeLogger.

Was this helpful?

On this page