Embed an AI voice agent with NowVoice

  • Release version: Zurich
  • Updated July 23, 2026
  • 3 minutes to read
  • Use the NowVoice module to embed a real-time AI voice agent session into your Android application.

    NowVoice features

    NowVoice gives your app a complete, ready-to-launch voice agent experience. When a user starts a voice agent session, the SDK:

    • Authenticates against your ServiceNow instance using the token your app provides.
    • Opens a WebSocket connection to the configured voice agent endpoint.
    • Launches a full-screen Activity with microphone controls and a live transcript.
    • Delivers real-time transcript messages and mute-state changes to your app through callbacks.
    • Shows an optional post-call transcript summary screen on session end.

    All public types in the NowVoice module are in the com.servicenow.nowsdk.voice package.

    Theming

    NowVoice integrates with the NowUI theming system. Implement NowVoiceTheme to apply custom colors. NowVoiceThemeDark is provided as a built-in alternative to the default light theme.

    Mobile SDK instance settings

    The NowVoice module reads the following keys from your ServiceNow instance's Mobile SDK settings response.

    {
      "voice": {
        "enabled": true,
        "configurations": [
          {
            "voiceServiceId": "String",
            "voiceWebhookURL": "String",
            "mobileChannelType": "String",
            "mobileChannelId": "String"
          }
        ]
      }
    }

    Configure NowVoice

    Configure NowVoice to add a real-time voice agent to your Android application.

    Before you begin

    Role required: admin

    • Mobile SDK 2.22.0 or later must be added to your project via Gradle.
    • Your ServiceNow instance must have voice agent services enabled. Confirm that sdk.voice.enabled is true in the Mobile SDK settings.

    Procedure

    1. Declare permissions in your app's AndroidManifest.xml.
      NowVoice requires microphone and internet permissions:
      <uses-permission android:name="android.permission.RECORD_AUDIO" />
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      Note:
      RECORD_AUDIO is a classified as a dangerous (runtime) permission. It must also be requested at runtime on Android 6.0 (API 23) and later. When permission is needed, NowVoice SDK automatically triggers a request before calling NowVoiceService.start().
    2. Configure NowSDK.
      If you have not already done so, call NowSDK.configure() once at app launch. NowVoice requires NowSDK to be configured before any voice operations.
      import com.servicenow.nowsdk.NowSDK
      import com.servicenow.nowsdk.NowSDKConfiguration
      
      NowSDK.configure(
          NowSDKConfiguration.Builder(this)
              .authorizationProvider(yourAuthProvider)
              .build()
      )
    3. Create a NowVoiceService.
      Import NowVoice and call NowVoiceSDK.makeVoiceService(instanceURL). This is a suspend function; call it from a coroutine scope.
      import com.servicenow.nowsdk.voice.NowVoiceSDK
      import kotlinx.coroutines.launch
      import java.net.URL
      
      lifecycleScope.launch {
          val result = NowVoiceSDK.makeVoiceService(
              instanceURL = URL("https://your-instance.service-now.com")
          )
      
          result
              .onSuccess { voiceService ->
                  // Service is ready; proceed to select an endpoint
              }
              .onFailure { error ->
                  // Handle NowServiceError
                  Log.e("NowVoice", "Service creation failed: $error")
              }
      }
    4. Select a voice endpoint.
      Use NowVoiceService.nowVoiceEndpoints to retrieve the available voice endpoints. In most apps there is a single endpoint.
      val endpoint = voiceService.nowVoiceEndpoints.firstOrNull() ?: return
    5. Launch the voice UI.
      Call start(context:endpoint:uiConfiguration:callbacks:theme:) to launch the full-screen voice agent Activity. This is a suspend function that returns after the session ends.
      voiceService.start(
          context = this@MainActivity,
          endpoint = endpoint,
          uiConfiguration = NowVoiceUiConfiguration(
              hidePostCallTranscript = false,
              shouldBlockAttachmentSharing = false
          ),
          callbacks = object : NowVoiceCallbacks {
              override fun onCallEnd(conversationId: String?, error: NowVoiceError?) {
                  if (error != null) {
                      Log.e("NowVoice", "Session ended with error: $error")
                  } else {
                      Log.d("NowVoice", "Session complete. ID: $conversationId")
                  }
              }
      
              override fun onMuteStateChanged(isMuted: Boolean) {
                  // Update your UI to reflect the current mute state
                  Log.d("NowVoice", "Microphone muted: $isMuted")
              }
      
              override fun onMessageReceived(message: TranscriptMessage) {
                  // Receive real-time transcript messages
                  Log.d("NowVoice", "${message.role}: ${message.content}")
              }
          },
          theme = object : NowVoiceTheme {}  // Uses default light theme
      )
    6. Optional: Apply a custom theme.
      // Prebuilt dark theme
      voiceService.start(context, endpoint, theme = NowVoiceThemeDark())
      
      // Custom theme
      val myTheme = object : NowVoiceTheme {
          override val primary: Int = Color.parseColor("#0072C6")
          override val backgroundPrimary: Int = Color.parseColor("#FFFFFF")
          // ... override additional properties as needed
      }
      
      // Apply theme at voice session launch
      voiceService.start(context, endpoint, theme = myTheme)
      
      // Or update theme while a voice session is active
      voiceService.updateTheme(NowVoiceThemeDark())

    Result

    The voice agent Activity launches full-screen. The user can begin a real-time voice session with transcript and mute-state updates delivered to your app through the configured callbacks.

    Complete example

    import com.servicenow.nowsdk.voice.*
    import kotlinx.coroutines.launch
    import java.net.URL
    
    class MainActivity : AppCompatActivity() {
    
        private fun launchVoiceSession() {
            lifecycleScope.launch {
                val result = NowVoiceSDK.makeVoiceService(
                    instanceURL = URL("https://your-instance.service-now.com")
                )
    
                result.onSuccess { voiceService ->
                    val endpoint = voiceService.nowVoiceEndpoints.firstOrNull() ?: return@onSuccess
    
                    voiceService.start(
                        context = this@MainActivity,
                        endpoint = endpoint,
                        callbacks = object : NowVoiceCallbacks {
                            override fun onCallEnd(conversationId: String?, error: NowVoiceError?) {
                                runOnUiThread { updateUI(ended = true) }
                            }
    
                            override fun onMuteStateChanged(isMuted: Boolean) {
                                runOnUiThread { updateMuteButton(isMuted) }
                            }
    
                            override fun onMessageReceived(message: TranscriptMessage) {
                                runOnUiThread { appendTranscript(message) }
                            }
                        }
                    )
                }.onFailure { error ->
                    Log.e("NowVoice", "Failed: $error")
                }
            }
        }
    }