Skip to main content
Version: 4.6.1

Basic Control Integration

Complete guide for implementing Basic Control with NetFUNNEL Android Agent using code-based integration.

Integration Methods

This is one of two integration methods available. See the Integration Methods Overview to compare with Section Control and choose the best approach for your use case.


How It Works

User Experience:

  1. User clicks button or triggers action
  2. Waiting room appears on current screen
  3. When entry allowed, waiting room closes and service continues

Best For:

  • Button click protection (login, checkout, order)
  • API call throttling
  • Precise control over specific actions

Key Difference from Section Control:

  • Basic Control: Controls entry speed (key returned quickly)
  • Section Control: Maintains fixed capacity (key held until section exit)

Prerequisites

Sample Application Examples

This guide uses a sample application to demonstrate Basic Control integration patterns. Your actual application code will differ from the examples shown. Focus on understanding the integration concepts and adapt the patterns to your specific codebase, function names, and business logic.

💡 Practice Template: Check out our Sample Projects for an Android Application (Single Activity) template ready for NetFUNNEL SDK integration practice.


Step 1: Create a Segment

Both Control Types Supported

Code-based Integration supports both Basic Control and Section Control. This guide uses Basic Control.

1.1 Create New Segment

  1. Go to NetFUNNEL console → ProjectsSegment
  2. Click the + button to create a new segment

Create segment button

1.2 Select Control Type

Choose Basic Control and click Next

Select Basic Control

1.3 Configure Segment

Segment Name: Enter a descriptive name (e.g., "Login Button", "Checkout Process", "API Call Protection")

Enter segment name

Entry Status:

  • Segment Activation enabled
  • Entry Status: Waiting (sends users to waiting room)

Entry status settings

Waiting Room Application:

  • Use default settings for testing
  • Leave Live Message blank

Waiting room settings

Limited Inflow:

  • Set to 0 for testing (no one admitted, waiting room always appears)

Limited inflow setting

1.4 Create Segment

Click Create to finalize the segment

Segment created


Step 2: Identify Key Issuance Integration Point (nfStart)

Sample Application

The following examples use a sample application for demonstration purposes. Your actual application code will naturally differ from what is shown here. Adapt the integration patterns to match your specific code structure, button IDs, function names, and business logic.

💡 Need a practice project? Check out our Sample Projects for an Android Application (Single Activity) template ready for NetFUNNEL SDK integration practice.

Understanding Our Sample Application:

Let's examine our sample application to understand where NetFUNNEL protection should be applied:

2.1 Identify the Target Button in Layout

<!-- fragment_main.xml -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/card_basic_control_function"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="12dp"
app:cardElevation="4dp"
app:rippleColor="?attr/colorPrimary"
app:strokeColor="?attr/colorPrimary"
app:strokeWidth="1dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/basic_control_function"
android:textAppearance="?attr/textAppearanceTitleLarge"
android:textColor="?attr/colorPrimary" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="@string/basic_control_function_desc"
android:textAppearance="?attr/textAppearanceBodyMedium" />

</LinearLayout>
</com.google.android.material.card.MaterialCardView>

Our Assumptions for This Sample:

  • The "Basic Control" button represents a resource-intensive operation
  • This could be: user login, payment processing, file upload, or data export
  • When many users click this button simultaneously, it could overwhelm the server
  • The other button is less critical and doesn't need protection

2.2 Find the Click Listener for This Button

What is a Click Listener?

A click listener (also called an event handler or click handler) is the code that executes when a user interacts with a UI element. In Android, this is typically defined using setOnClickListener() method or lambda expressions.

Understanding Android Click Listener Structure:

// Method 1: Lambda expression (most common)
button.setOnClickListener {
// 🎯 THIS IS THE CLICK LISTENER
// Code here runs when user taps the button
}

// Method 2: Anonymous object (traditional)
button.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
// 🎯 THIS IS THE CLICK LISTENER
// Code here runs when user taps the button
}
})

In Our Sample Application:

// MainFragment.kt
override fun setupViews() {
// 🎯 TARGET BUTTON: Basic Control Function Card
binding.cardBasicControlFunction.setOnClickListener {
// 🎯 CLICK LISTENER: This is where the button action is defined
// This is the code that runs when user clicks the button
// Currently: navigationManager.navigateWithDelay() executes immediately
// We will wrap this with NetFUNNEL protection
Log.d("MainActivity", "Basic Control (Code-based Integration) button clicked")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}

// Other button - not our target (no NetFUNNEL protection needed)
binding.cardSectionControlFunction.setOnClickListener {
// This button doesn't need NetFUNNEL protection
Log.d("MainActivity", "Section Control Function button clicked")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_sectionControlSection1Fragment
)
}
}
}

Key Points:

  • Click Listener Location: Inside the setOnClickListener lambda
  • Current Action: navigationManager.navigateWithDelay() executes immediately
  • Integration Target: This is where we'll add NetFUNNEL protection

2.3 Examine What Happens Inside the Click Listener

What the function does:

// NavigationManager.kt
suspend fun navigateWithDelay(
resId: Int,
customDelay: Long? = null
) {
val delay = customDelay ?: appPreferences.getNavigationDelay()

showLoadingIndicator() // ← Shows loading indicator
delay(delay) // ← Waits for specified time
hideLoadingIndicator() // ← Hides loading indicator

navController?.navigate(resId) // ← Navigates to target fragment
}

Summary: Shows loading → Waits → Hides loading → Navigates. This simulates server processing and needs NetFUNNEL protection.

2.4 Identify the Integration Point

  1. Target Button: card_basic_control_function (the resource-intensive one)
  2. Click Listener: setupViews() method sets up the click handler
  3. Integration Location: Right before navigationManager.navigateWithDelay() is called
  4. Why Here: This is the exact moment before server processing begins
  5. Protection Strategy: Add NetFUNNEL queue before the server call

Complete Flow Analysis:

  1. Fragment Creation: onViewCreated() calls setupViews()
  2. Button Setup: setupViews() sets up click listeners for each button
  3. User Action: User clicks "Basic Control (Code-based Integration)" button
  4. Current Behavior: navigationManager.navigateWithDelay() executes immediately
  5. Server Load: This triggers the resource-intensive operation

The Logic:

  • Without NetFUNNEL: Button click → Immediate server request → Potential overload
  • With NetFUNNEL: Button click → Queue check → Controlled server request → Success

Step 3: Implement Key Issuance Function (nfStart)

Adapt to Your Code

The example below shows how to integrate NetFUNNEL into the sample application's MainFragment click handler. Adapt this pattern to your actual code structure - you may have different function names, event handlers, or business logic that needs protection.

3.1 Get Your Keys

First, find your Project Key and Segment Key in the console:

  1. Go to NetFUNNEL console → ProjectsSegment
  2. Click on your segment
  3. Copy the Project Key and Segment Key

Project and segment keys

3.2 Understand the nfStart Function

The nfStart function has this basic structure:

Netfunnel.nfStart(
projectKey = "your_project_key", // From console
segmentKey = "your_segment_key", // From console
callback = yourCallback, // Callback to handle response
activity = this // Current activity context
)
API Reference

For complete details about nfStart parameters, callback handling, and response formats, see the API Reference.

3.3 Start with Your Current Code

Current Implementation:

// MainFragment.kt
override fun setupViews() {
binding.cardBasicControlFunction.setOnClickListener {
Log.d("MainActivity", "Basic Control (Code-based Integration) button clicked")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}
}

The Core Concept:

  • Business Logic: navigationManager.navigateWithDelay() represents a resource-intensive operation
  • Integration Point: We need to wrap this business logic with NetFUNNEL protection
  • Wrapping Strategy: Use nfStart() to control access before the business logic executes

Why Wrap Here:

  • This is the exact moment before server load begins
  • Wrapping here protects the entire downstream operation
  • The business logic remains unchanged - we just add a queue layer

3.4 Add Required Imports

Before implementing NetFUNNEL, add the necessary imports to your Fragment:

// MainFragment.kt
import com.nf4.Netfunnel
import com.nf4.NetfunnelCallback

Key Imports:

  • com.nf4.Netfunnel - Main NetFUNNEL class
  • com.nf4.NetfunnelCallback - Callback interface for responses

3.5 Add Basic NetFUNNEL Protection (Success Only)

Wrap the Business Logic:

// MainFragment.kt
import com.nf4.Netfunnel
import com.nf4.NetfunnelCallback

override fun setupViews() {
binding.cardBasicControlFunction.setOnClickListener {
Log.d("MainActivity", "Basic Control (Code-based Integration) button clicked")
startBasicControl()
}

binding.cardSectionControlFunction.setOnClickListener {
Log.d("MainActivity", "Section Control Function button clicked")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_sectionControlSection1Fragment
)
}
}
}

private fun startBasicControl() {
Netfunnel.nfStart(
projectKey = "your_project_key",
segmentKey = "your_segment_key",
callback = basicControlCallback,
activity = requireActivity()
)
}

private val basicControlCallback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
// User can proceed - execute original logic
Log.d("NetFUNNEL", "onSuccess(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}

override fun onBlock(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onBlock(statusCode=$statusCode, message='$message')")
}

override fun onClose(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onClose(statusCode=$statusCode, message='$message')")
}

override fun onContinue(
statusCode: Int,
message: String,
aheadWait: Int,
behindWait: Int,
waitTime: String,
progressRate: Int
) {
Log.d("NetFUNNEL", "onContinue(statusCode=$statusCode, message='$message', aheadWait=$aheadWait, behindWait=$behindWait, waitTime='$waitTime', progressRate=$progressRate)")
}

override fun onError(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onError(statusCode=$statusCode, message='$message')")
}

override fun onNetworkError(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onNetworkError(statusCode=$statusCode, message='$message')")
}
}

What Changed:

  • Wrapped: navigationManager.navigateWithDelay() is now inside the onSuccess callback
  • Conditional: Only the specific button gets NetFUNNEL protection
  • Success-Only: Business logic runs only when NetFUNNEL allows entry
  • Complete Interface: All required callback methods are implemented with proper logging
Android Interface Requirements

In Android, NetfunnelCallback is an interface that requires implementing ALL methods. You cannot implement only onSuccess - you must provide implementations for all callback methods. This implementation provides complete callback handling with proper logging for all response types.

Now let's test your implementation to make sure everything is working correctly.

Run your app and click the "Basic Control (Code-based Integration)" button. You should see a waiting room WebView appear on your screen. To verify everything is working properly, check the Logcat for NetFUNNEL logs.

If No Waiting Room Appears

If you don't see the waiting room, make sure you set Limited Inflow to 0 in the Configure Segment step. This setting controls whether users are sent to the waiting room or allowed to proceed directly.

Enable NetFUNNEL Logging for Better Debugging:

Enable debug logging by setting printLog = true in your Application class, then filter Logcat with package:mine NetFUNNEL. For detailed setup instructions, see the Test NetFUNNEL Initialization) section.

What to Look For:

When you click the Basic Control button with Limited Inflow = 0, you should see logs like this:

2025-09-15 14:21:45.762  5659-5659  NetFUNNEL               com...ample_android_single_activity  D  [NF4] Initialization successful. NetFUNNEL Version: 4.3.3-onprem
2025-09-15 14:21:52.685 5659-5675 NetFUNNEL com...ample_android_single_activity D [NF4] Initial entry detected. Request(5101), Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 14:21:52.727 5659-5677 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5101 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
2025-09-15 14:21:54.177 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5101 response. Response(timestamp=1757913714588, code=201, msg=null, key=A06C985C93A27FA585B6EB31707D8F75560B09C0ABA476E93DAAFF65D8F81E1F2AA6D7A151BC9D46A7A70B04309F5684BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 14:21:54.184 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Loading the virtual room. Work(projectKey=service_1, segmentKey=test_liam_01), Status(WAIT)
2025-09-15 14:21:55.745 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Fetching HTML content from following URL. https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html
2025-09-15 14:21:56.368 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=A06C985C93A27FA585B6EB31707D8F75560B09C0ABA476E93DAAFF65D8F81E1F2AA6D7A151BC9D46A7A70B04309F5684BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30&sticky=nf1
2025-09-15 14:21:56.406 5659-5765 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757913717559, code=201, msg=null, key=A06C985C93A27FA585B6EB31707D8F7501186C02D6377624BD336C0B9EABC7B23E0DA90D4459587BF1B066C976432A52BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D31302C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)

Key indicators that everything is working:

Log MessageWhat It MeansStatus
[NF4] Initialization successfulNetFUNNEL agent loaded correctly✅ Good
[NF4] Initial entry detectednfStart() was called successfully✅ Good
[NF4] Sending 5101 requestRequest sent to NetFUNNEL server✅ Good
[NF4] Received 5101 response with code=201Server responded with WAIT status✅ Good
[NF4] Loading the virtual roomWaiting room WebView is loading✅ Good
[NF4] Fetching HTML contentWaiting room HTML is being loaded✅ Good
[NF4] Sending 5002 requestPeriodic re-entry requests (polling)✅ Good

If you encounter issues:

  • No logs appear: Check if printLog = true is set in initialization
  • No waiting room: Verify Limited Inflow is set to 0 in console
  • App crashes: Check if all callback methods are implemented properly
  • Network errors: Verify clientId and network connectivity

If you see the waiting room and logs, your basic implementation is working! You can now proceed to enhance the callback handling for better error management. To test entry, change Limited Inflow to 1 in the console.

3.6 Add Complete Callback Handling

Now let's improve the callback handling for better error management and user experience:

In the previous step, we implemented all callback methods with basic logging. Now we'll enhance the error handling to ensure robust service availability and optimal user experience in production environments.

Why Complete Callback Handling is Essential:

  • User Experience: Different response types need appropriate user feedback
  • Service Reliability: Error states should not break the user's workflow
  • Debugging: Comprehensive logging helps identify issues quickly
  • Business Continuity: Service should continue even when NetFUNNEL encounters problems

Enhance your basicControlCallback with robust error handling:

// MainFragment.kt - Updated basicControlCallback with complete handling
private val basicControlCallback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
// User can proceed - execute original logic
Log.d("NetFUNNEL", "onSuccess(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}

override fun onError(statusCode: Int, message: String) {
// System error occurred - proceed with original logic for robust service availability
Log.d("NetFUNNEL", "onError(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}

override fun onNetworkError(statusCode: Int, message: String) {
// Network error occurred - log for debugging, but don't execute business logic
Log.d("NetFUNNEL", "onNetworkError(statusCode=$statusCode, message='$message')")
// Note: Business logic not executed here - see explanation below
}

override fun onBlock(statusCode: Int, message: String) {
// User is blocked - show appropriate message
Log.d("NetFUNNEL", "onBlock(statusCode=$statusCode, message='$message')")
}

override fun onClose(statusCode: Int, message: String) {
// User closed waiting room - handle appropriately
Log.d("NetFUNNEL", "onClose(statusCode=$statusCode, message='$message')")
// Stay on main fragment - user canceled
}

override fun onContinue(
statusCode: Int,
message: String,
aheadWait: Int,
behindWait: Int,
waitTime: String,
progressRate: Int
) {
Log.d("NetFUNNEL", "onContinue(statusCode=$statusCode, message='$message', aheadWait=$aheadWait, behindWait=$behindWait, waitTime='$waitTime', progressRate=$progressRate)")
}
}

Response Handling Strategy:

Response TypeActionBusiness Logic
SuccessExecute✅ Yes
ErrorExecute✅ Yes
NetworkErrorLog Only❌ No
BlockLog Only❌ No
CloseLog Only❌ No
ContinueLog Only❌ No

Why onError Executes Business Logic but onNetworkError Doesn't:

onError (Status Code 500) - Server Error:

  • Scenario: NetFUNNEL server encounters internal errors
  • Strategy: Execute business logic to maintain service availability
  • Rationale: Server errors are typically temporary and shouldn't block user access
  • Result: Robust service that continues even when NetFUNNEL has issues

onNetworkError (Status Code 1001, 1002) - Network Issues:

  • Scenario: Network connectivity problems (offline, timeout)
  • Strategy: Log only, don't execute business logic
  • Rationale: Use useNetworkRecoveryMode = true for automatic network recovery
  • Result: Users stay in waiting room during network issues and auto-resume when connectivity returns

Network Recovery Mode Configuration:

Enable network recovery in your Application class for optimal network error handling:

// SampleApplication.kt
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
useNetworkRecoveryMode = true // Enable automatic network recovery
)

What Changed:

  • Robust error handling: onError proceeds with business logic for maximum service availability
  • Smart network handling: onNetworkError relies on network recovery mode instead of manual handling
  • Improved user experience: Better handling of different response states
  • Production-ready: Robust error handling ensures service continues even when NetFUNNEL encounters issues
  • Comprehensive logging: Detailed console messages for all response types and debugging
Complete API Reference

For detailed information about all callback response types, status codes, response object structure, and advanced callback patterns, see the API Reference.

3.7 Key Implementation Points

  1. Project/Segment keys: Use exact keys from the NetFUNNEL console
  2. Required imports: Add com.nf4.Netfunnel and com.nf4.NetfunnelCallback imports
  3. Callback implementation: Implement ALL callback methods (Android interface requirement)
  4. Robust error handling:
    • onSuccess and onError execute business logic for service availability
    • onNetworkError logs only (use useNetworkRecoveryMode = true for automatic recovery)
  5. Activity context: Always pass the current activity context to nfStart()
  6. Comprehensive logging: Log all callback responses for debugging

Step 4: Identify Key Return Integration Point (nfStop)

Sample Application

The following examples use a sample application for demonstration purposes. Your actual application code will naturally differ from what is shown here. Adapt the integration patterns to match your specific code structure, business logic completion points, and key return requirements.

💡 Need a practice project? Check out our Sample Projects for an Android Application (Single Activity) template ready for NetFUNNEL SDK integration practice.

Understanding Our Sample Application:

Let's examine our sample application to understand where nfStop should be called to return the NetFUNNEL key.

4.1 Identify Business Logic Completion Points

Current Flow After nfStart Success:

// From Step 3 - when nfStart succeeds
override fun onSuccess(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "onSuccess(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}

What Happens Next:

  1. User navigates to BasicControlFragment - Fragment lifecycle begins
  2. Fragment loads completely - onCreateView(), setupViews() complete
  3. User's session is active - they can now use the protected functionality
  4. Key should be returned - to allow the next user in queue to enter

Important Note about nfStop Implementation: nfStop can be called independently without requiring nfStart to be called first. If nfStart was never called, NetFUNNEL will automatically handle the key release if needed, or do nothing if no key exists. This makes nfStop safe to call in any scenario without conditional checks, simplifying the implementation.

4.2 Identify Integration Points for Key Return

Integration Point Options:

Integration PointWhen to UsePros
Fragment LifecycleSimple navigation flowsEasy to implement, works for most cases
Business Logic CompletionComplex operations (API calls, processing)Precise control, returns key after actual work
User Action CompletionUser-initiated operationsReturns key when user finishes their task

4.3 Choose the Right Integration Point

For Our Sample Application:

Current Business Logic: navigationManager.navigateWithDelay()

  • What it does: Simulates server processing and navigates to BasicControlFragment
  • When it completes: When the BasicControlFragment loads successfully
  • Best integration point: Fragment lifecycle events (onViewCreated, setupViews)

Integration Strategy:

  1. Fragment Creation: Return key when BasicControlFragment is fully loaded
  2. Simple and Reliable: Works for navigation-based flows
  3. User Experience: Key is returned when user can actually use the service

4.4 Verify Integration Point Logic

Complete Flow Analysis:

  1. User clicks buttonnfStart() called
  2. Waiting room appears → User waits in queue
  3. Entry grantedonSuccess callback fires
  4. Business logic executesnavigationManager.navigateWithDelay() runs
  5. BasicControlFragment loads → User can now use the service
  6. Key return needed → Call nfStop() to free up queue slot

Why This Integration Point Makes Sense:

  • User Experience: Key is returned when user can actually use the service
  • Queue Management: Next user can enter as soon as current user is ready
  • Resource Efficiency: Prevents unnecessary queue blocking
  • Implementation Simplicity: Easy to implement and maintain

Key Insight: The nfStop integration point should be where the user's intended business operation is truly complete and they can benefit from the service they queued for.


Step 5: Implement Key Return Function (nfStop)

Adapt to Your Application

The examples below show different approaches for returning keys. Choose the approach that best fits your application's architecture - whether you need to return keys after Fragment navigation, API calls, or other business logic completion.

5.1 Understand the nfStop Function

The nfStop function has this basic structure:

Netfunnel.nfStop(
projectKey = "your_project_key", // Must match nfStart keys exactly
segmentKey = "your_segment_key", // Must match nfStart keys exactly
completeCallback = yourCompleteCallback // Callback to handle completion
)

Java equivalent:

Netfunnel.INSTANCE.nfStop(
"your_project_key", // Must match nfStart keys exactly
"your_segment_key", // Must match nfStart keys exactly
yourCompleteCallback // Callback to handle completion
);

Key Requirements:

  • Exact Key Matching: Keys must be identical to those used in nfStart()
  • Timing: Call after business logic completes, not immediately after nfStart()
  • Callback: Use NetfunnelCompleteCallback to handle completion response

5.2 Add Required Imports

Before implementing nfStop, add the necessary imports to your Fragment:

// BasicControlFragment.kt
import com.nf4.Netfunnel
import com.nf4.NetfunnelCompleteCallback

Key Imports:

  • com.nf4.Netfunnel - Main NetFUNNEL class (already imported for nfStart)
  • com.nf4.NetfunnelCompleteCallback - Callback interface for key return completion

5.3 Add Basic Key Return (Fragment Lifecycle)

Return key when BasicControlFragment loads:

// BasicControlFragment.kt
import com.nf4.Netfunnel
import com.nf4.NetfunnelCompleteCallback

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

// Return key when fragment is fully loaded
Netfunnel.nfStop(
projectKey = "your_project_key",
segmentKey = "your_segment_key",
completeCallback = completeCallback
)
}

private val completeCallback = object : NetfunnelCompleteCallback() {
override fun onComplete(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "Key returned: $message")
}
}

What Changed:

  • Fragment Lifecycle: Returns key when BasicControlFragment is fully loaded
  • Simple Approach: Works for basic navigation scenarios
  • Direct Call: Assumes NetFUNNEL is initialized and available

Now let's test your key return implementation to make sure everything is working correctly.

Run your app and follow this testing sequence:

  1. Click the "Basic Control (Code-based Integration)" button - You should see the waiting room appear
  2. In NetFUNNEL console, change Limited Inflow from 0 to 1 - This allows entry
  3. Observe the waiting room closing - It should disappear and navigate to BasicControlFragment
  4. Check Logcat for key return logs - You should see 5004 request logs

Enable NetFUNNEL Logging for Better Debugging:

Enable debug logging by setting printLog = true in your Application class, then filter Logcat with package:mine NetFUNNEL. For detailed setup instructions, see the Test NetFUNNEL Initialization) section.

What to Look For:

When you change Limited Inflow from 0 to 1 during the waiting room phase, you should see logs like this:

2025-09-15 15:23:33.864  6196-6196  NetFUNNEL               com...ample_android_single_activity  D  [NF4] Initialization successful. NetFUNNEL Version: 4.3.3-onprem
2025-09-15 15:23:46.203 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Initial entry detected. Request(5101), Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 15:23:46.227 6196-6211 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5101 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
2025-09-15 15:23:47.726 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5101 response. Response(timestamp=1757917427984, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB1898D3FBDDED79E1C4979B70CAECA7D2F9071C98595486C24B070C0DFEB954A9C3F4BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D382C312C312C302C302C302C30, nwait=1, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:47.736 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Loading the virtual room. Work(projectKey=service_1, segmentKey=test_liam_01), Status(WAIT)
2025-09-15 15:23:48.426 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Fetching HTML content from following URL. https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html
2025-09-15 15:23:48.817 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB1898D3FBDDED79E1C4979B70CAECA7D2F9071C98595486C24B070C0DFEB954A9C3F4BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D382C312C312C302C302C302C30&sticky=nf1
2025-09-15 15:23:48.887 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917430008, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB189855B40CD9D2F33B8E94212241C974E92C78785D8C84A0E36FBF42A696FD0C9265BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D362C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:49.897 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB189855B40CD9D2F33B8E94212241C974E92C78785D8C84A0E36FBF42A696FD0C9265BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D362C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:49.924 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917431061, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB1898D2071B63927D1DD62706C0078BC432511A923D0082FE30F53FB1965DB63DF0BCBCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D352C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:50.929 6196-6285 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB1898D2071B63927D1DD62706C0078BC432511A923D0082FE30F53FB1965DB63DF0BCBCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D352C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:50.951 6196-6285 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917432090, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB189829DB6FFDBB6FB013CEA7F6599A9C94129D63CE6AE1AB4B557C31685803153728BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:51.956 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB189829DB6FFDBB6FB013CEA7F6599A9C94129D63CE6AE1AB4B557C31685803153728BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D342C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:51.979 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917433117, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB1898CD1CF597D3764F52F1B11FE6F5A1DA1AB8B301E456A85CF6D2D35F5C17F33784BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D332C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:52.984 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB1898CD1CF597D3764F52F1B11FE6F5A1DA1AB8B301E456A85CF6D2D35F5C17F33784BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D332C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:53.007 6196-6212 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917434146, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB189802E99D6C9B4A367F1C40935A4D05C854DCFC137D2FD253A3CE5B0E8EE2359C11BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:54.012 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB189802E99D6C9B4A367F1C40935A4D05C854DCFC137D2FD253A3CE5B0E8EE2359C11BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:54.044 6196-6289 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917435174, code=201, msg=null, key=B32E23DD6D61705669BE18E213CB1898AA690315A075EC205F9ADE7559D9E5CE2C7130F9371987B6C74547C61F6112E4BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D302C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 15:23:55.050 6196-6287 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=B32E23DD6D61705669BE18E213CB1898AA690315A075EC205F9ADE7559D9E5CE2C7130F9371987B6C74547C61F6112E4BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D302C312C302C302C302C302C30&sticky=nf1
2025-09-15 15:23:55.076 6196-6286 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757917436212, code=200, msg=null, key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=0, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=null, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=1)
2025-09-15 15:23:55.088 6196-6286 NetFUNNEL com...ample_android_single_activity D [NF4] "Success" response from NetFUNNEL Server.
2025-09-15 15:23:55.088 6196-6286 NetFUNNEL com...ample_android_single_activity D onSuccess(statusCode=200, message='Success')
2025-09-15 15:23:56.143 6196-6196 VRI[NetfunnelWebView] com...ample_android_single_activity D visibilityChanged oldVisibility=true newVisibility=false
2025-09-15 15:23:56.380 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Key return attempt detected. Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 15:23:56.383 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5004 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5004&key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30&sticky=nf1
2025-09-15 15:23:56.441 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5004 response. Response(timestamp=1757917437568, code=200, msg=null, key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=0, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=null, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=1)
2025-09-15 15:23:56.443 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] "Success" response from NetFUNNEL Server.
2025-09-15 15:23:56.448 6196-6288 NetFUNNEL com...ample_android_single_activity D Key returned: Key Return Successful

Key indicators that everything is working:

Log MessageWhat It MeansStatus
[NF4] Initial entry detectednfStart() was called successfully✅ Good
[NF4] Loading the virtual roomWaiting room WebView is loading✅ Good
[NF4] Sending 5002 request (repeated)Periodic re-entry requests (polling)✅ Good
[NF4] Received 5002 response with code=200Entry granted - waiting room should close✅ Good
onSuccess(statusCode=200, message='Success')Success callback fired✅ Good
visibilityChanged oldVisibility=true newVisibility=falseWaiting room WebView closed✅ Good
[NF4] Key return attempt detectednfStop() was called✅ Good
[NF4] Sending 5004 requestKey return request sent to server✅ Good
[NF4] Received 5004 response with code=200Key return successful✅ Good
Key returned: Key Return SuccessfulComplete callback fired✅ Good

Testing Sequence:

  1. Start with Limited Inflow = 0: Waiting room appears, 5002 requests repeat
  2. Change Limited Inflow to 1: 5002 response changes to code=200, waiting room closes
  3. Fragment loads: BasicControlFragment onViewCreated() calls nfStop()
  4. Key return: 5004 request/response confirms key return

If you encounter issues:

  • No 5004 logs: Check if nfStop() is being called in BasicControlFragment
  • Key return fails: Verify project/segment keys match exactly between nfStart() and nfStop()
  • Fragment doesn't load: Check if onSuccess callback is executing navigation properly
  • Waiting room doesn't close: Verify Limited Inflow is set to 1 in console

If you see the complete flow from waiting room → entry → fragment load → key return, your implementation is working correctly! You can now proceed to enhance the error handling and add more robust callback management.

5.4 Key Implementation Points

Best Practice: Return Keys Promptly

Return NetFUNNEL keys when your business logic completes. While NetFUNNEL automatically returns keys after timeout, manual returns provide better user experience and queue efficiency.

Key Return Rules:

  • Always: Return key after business logic completes (success or failure)
  • ⚠️ Auto-timeout: NetFUNNEL returns keys automatically if not returned manually
  • Timing: Call after business logic completes, not immediately after nfStart()

Implementation Checklist:

  1. Exact Key Matching: Keys in nfStop() must match nfStart() exactly
  2. Fragment Lifecycle: Use onViewCreated() for key return timing
  3. Complete Callback: Always implement NetfunnelCompleteCallback for completion handling
  4. Consistent Keys: Use the same project/segment keys throughout the flow
Complete API Reference

For detailed information about nfStop parameters, response handling, and advanced key return patterns, see the API Reference.


Step 6: Test Waiting Room (Limited Inflow = 0)

Testing with Your Application

The testing steps below are based on the sample application. Adapt the testing process to your actual application - replace button names, fragment navigation, and verification steps with your specific implementation.

6.1 Trigger the Action

  1. Clear Logcat logs (if you want to observe from a clean state)

    • In Android Studio, click the trash icon in Logcat to clear previous logs
    • Or use command: adb logcat -c
  2. Click the protected button (e.g., "Basic Control (Code-based Integration)" button)

Expected result: Waiting room WebView appears on current screen

Android main screen before clicking Android waiting room WebView

6.2 Verify Waiting Room Display

Check these elements are shown correctly:

With Limited Inflow set to 0 and only one user connected, verify:

  • My waiting number: 1
  • Estimated Wait Time: 00:00:00 (hh:mm:ss)
  • Queue behind: 0
Android waiting room WebView

6.3 Check Logcat Activity

Verify NetFUNNEL logs:

Enable debug logging by setting printLog = true in your Application class, then filter Logcat with package:mine NetFUNNEL. You should see logs like:

2025-09-15 14:21:45.762  5659-5659  NetFUNNEL               com...ample_android_single_activity  D  [NF4] Initialization successful. NetFUNNEL Version: 4.3.3-onprem
2025-09-15 14:21:52.685 5659-5675 NetFUNNEL com...ample_android_single_activity D [NF4] Initial entry detected. Request(5101), Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 14:21:52.727 5659-5677 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5101 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5101&sid=service_1&aid=test_liam_01
2025-09-15 14:21:54.177 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5101 response. Response(timestamp=1757913714588, code=201, msg=null, key=A06C985C93A27FA585B6EB31707D8F75560B09C0ABA476E93DAAFF65D8F81E1F2AA6D7A151BC9D46A7A70B04309F5684BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)
2025-09-15 14:21:54.184 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Loading the virtual room. Work(projectKey=service_1, segmentKey=test_liam_01), Status(WAIT)
2025-09-15 14:21:55.745 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Fetching HTML content from following URL. https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html
2025-09-15 14:21:56.368 5659-5676 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5002 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5002&key=A06C985C93A27FA585B6EB31707D8F75560B09C0ABA476E93DAAFF65D8F81E1F2AA6D7A151BC9D46A7A70B04309F5684BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D322C312C302C302C302C302C30&sticky=nf1
2025-09-15 14:21:56.406 5659-5765 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5002 response. Response(timestamp=1757913717559, code=201, msg=null, key=A06C985C93A27FA585B6EB31707D8F7501186C02D6377624BD336C0B9EABC7B23E0DA90D4459587BF1B066C976432A52BCFD08B8F833299D4D743DBF3C84B6D4359F81879079494C2A0482939478A897459E4B85A186035300FD8474FD450E3D31302C312C302C302C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=1, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=wait, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=0)

Key indicators that everything is working:

Log MessageWhat It MeansStatus
[NF4] Initialization successfulNetFUNNEL agent loaded correctly✅ Good
[NF4] Initial entry detectednfStart() was called successfully✅ Good
[NF4] Sending 5101 requestRequest sent to NetFUNNEL server✅ Good
[NF4] Received 5101 response with code=201Server responded with WAIT status✅ Good
[NF4] Loading the virtual roomWaiting room WebView is loading✅ Good
[NF4] Fetching HTML contentWaiting room HTML is being loaded✅ Good
[NF4] Sending 5002 requestPeriodic re-entry requests (polling)✅ Good
[NF4] Received 5002 response with code=201Server responded with WAIT status✅ Good

Verify response:

  • Look for ts.wseq?opcode=5002 requests in the logs
  • Check response shows code=201 (WAIT)
  • 201 = WAIT, 200 = PASS (entry allowed)
  • Here, since Limited Inflow is 0, the correct response is 201

Step 7: Test Entry (Limited Inflow = 1)

7.1 Update Segment Settings

  1. Return to NetFUNNEL console
  2. Click segment's Edit button to open the edit screen

NetFUNNEL console edit segment button

  1. Change Limited Inflow from 0 to 1
  2. Click Confirm at the bottom

Update limited inflow Confirm changes

Immediate Effect

As soon as you click Confirm, the waiting room will disappear and you will immediately navigate to BasicControlFragment. If you want to observe this moment, keep another screen open where the waiting room is currently displayed.

7.2 Verify Entry

Expected result: Waiting room disappears immediately, navigation to BasicControlFragment occurs

Android service entry successful

Check Logcat for entry confirmation:

You should see logs like:

2025-09-15 15:23:55.076  6196-6286  NetFUNNEL               com...ample_android_single_activity  D  [NF4] Received 5002 response. Response(timestamp=1757917436212, code=200, msg=null, key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=0, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=null, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=1)
2025-09-15 15:23:55.088 6196-6286 NetFUNNEL com...ample_android_single_activity D [NF4] "Success" response from NetFUNNEL Server.
2025-09-15 15:23:55.088 6196-6286 NetFUNNEL com...ample_android_single_activity D onSuccess(statusCode=200, message='Success')
2025-09-15 15:23:56.143 6196-6196 VRI[NetfunnelWebView] com...ample_android_single_activity D visibilityChanged oldVisibility=true newVisibility=false

Key indicators of successful entry:

Log MessageWhat It MeansStatus
[NF4] Received 5002 response with code=200Entry granted - waiting room should close✅ Good
[NF4] "Success" response from NetFUNNEL ServerSuccess response received✅ Good
onSuccess(statusCode=200, message='Success')Success callback fired✅ Good
visibilityChanged oldVisibility=true newVisibility=falseWaiting room WebView closed✅ Good

7.3 Check Key Return

Verify successful key return:

Look for these logs in Logcat:

2025-09-15 15:23:56.380  6196-6213  NetFUNNEL               com...ample_android_single_activity  D  [NF4] Key return attempt detected. Work(projectKey=service_1, segmentKey=test_liam_01), Control(BASIC)
2025-09-15 15:23:56.383 6196-6213 NetFUNNEL com...ample_android_single_activity D [NF4] Sending 5004 request. https://nf4-onprem-demo-4525.stclab.com/ts.wseq?opcode=5004&key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30&sticky=nf1
2025-09-15 15:23:56.441 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] Received 5004 response. Response(timestamp=1757917437568, code=200, msg=null, key=B32E23DD6D61705669BE18E213CB1898A1CB5D9BE6372F442714047E95693E10AD2F823D01AAF9EB91D8F2962E28A0031F1A3257C7780F8C2A1A1CBDFBB5888170442F1BB67CC53F28D02A19B48CDEE2071A87CC017BE50129F11B1499A36DF69C95FE37D4AB7D6900A9DFF3D496CDB1312C302C302C30, nwait=0, nnext=0, tps=0.0, ttl=0, ip=nf4-onprem-demo-4525.stclab.com, port=443, vwrHtml=https://nf4-onprem-demo-4525.stclab.com/content/netfunnel-statics/assets/vwr-page/page/1/1/1/index.html, vwrType=null, preBeginTs=null, preEndTs=null, postBeginTs=null, postEndTs=null, sticky=nf1, liveMessage=null, chkEnterCnt=1)
2025-09-15 15:23:56.443 6196-6288 NetFUNNEL com...ample_android_single_activity D [NF4] "Success" response from NetFUNNEL Server.
2025-09-15 15:23:56.448 6196-6288 NetFUNNEL com...ample_android_single_activity D Key returned: Key Return Successful

Key indicators of successful key return:

Log MessageWhat It MeansStatus
[NF4] Key return attempt detectednfStop() was called✅ Good
[NF4] Sending 5004 requestKey return request sent to server✅ Good
[NF4] Received 5004 response with code=200Key return successful✅ Good
Key returned: Key Return SuccessfulComplete callback fired✅ Good

Summary

Essential Points (Must Do)

Setup:

  • Complete Installation & Initialization and verify NetFUNNEL agent loads correctly
  • Create segment in console with Basic Control
  • Get Project Key and Segment Key from console
  • Set Limited Inflow to 0 for testing, 1+ for production

Integration:

  • Add required imports: com.nf4.Netfunnel and com.nf4.NetfunnelCallback
  • Implement ALL callback methods (Android interface requirement)
  • Wrap business logic with Netfunnel.nfStart() in click handlers
  • Handle onSuccess callback to execute business logic
  • Call Netfunnel.nfStop() after business logic completes
  • Use identical keys in both nfStart() and nfStop()

Error Handling:

  • Handle onError by proceeding with business logic (maintains service availability)
  • Handle onNetworkError by logging only (use useNetworkRecoveryMode = true)
  • Handle onBlock by showing appropriate user message
  • Handle onClose by staying on current fragment (user canceled)
  • Implement comprehensive logging for all callback responses

Testing:

  • Test waiting room appears with Limited Inflow = 0
  • Test entry works with Limited Inflow = 1
  • Verify key return occurs after completion
  • Check Logcat for NetFUNNEL logs with package:mine NetFUNNEL filter

Optional Items (Nice to Have)

Error Handling Enhancements:

  • Add user-friendly error messages instead of basic logging
  • Implement custom error handling strategies for different response types
  • Add analytics tracking for NetFUNNEL events

Code Organization:

  • Create centralized configuration constants
  • Build reusable NetFUNNEL wrapper functions
  • Implement modular integration patterns across multiple fragments

Best Practices

Required Imports

import com.nf4.Netfunnel
import com.nf4.NetfunnelCallback
import com.nf4.NetfunnelCompleteCallback

Why these imports matter:

  • Essential for NetFUNNEL integration
  • Must be added to any Fragment/Activity using NetFUNNEL
  • Required for both nfStart() and nfStop() functions

Complete Callback Implementation

private val basicControlCallback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
// Execute business logic when entry is granted
Log.d("NetFUNNEL", "onSuccess(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}

override fun onError(statusCode: Int, message: String) {
// System error - proceed anyway to maintain service availability
Log.d("NetFUNNEL", "onError(statusCode=$statusCode, message='$message')")
lifecycleScope.launch {
navigationManager.navigateWithDelay(
R.id.action_mainFragment_to_basicControlFragment
)
}
}

override fun onNetworkError(statusCode: Int, message: String) {
// Network error - log only, rely on network recovery mode
Log.d("NetFUNNEL", "onNetworkError(statusCode=$statusCode, message='$message')")
// Business logic not executed here - see explanation below
}

override fun onBlock(statusCode: Int, message: String) {
// User is blocked - show appropriate message
Log.d("NetFUNNEL", "onBlock(statusCode=$statusCode, message='$message')")
}

override fun onClose(statusCode: Int, message: String) {
// User closed waiting room - handle appropriately
Log.d("NetFUNNEL", "onClose(statusCode=$statusCode, message='$message')")
// Stay on main fragment - user canceled
}

override fun onContinue(
statusCode: Int,
message: String,
aheadWait: Int,
behindWait: Int,
waitTime: String,
progressRate: Int
) {
Log.d("NetFUNNEL", "onContinue(statusCode=$statusCode, message='$message', aheadWait=$aheadWait, behindWait=$behindWait, waitTime='$waitTime', progressRate=$progressRate)")
}
}

Key principle: Always implement ALL callback methods - Android interface requirement.

Centralized Configuration

// Store your keys in one place
companion object {
private const val PROJECT_KEY = "your_project_key"
private const val SEGMENT_KEY = "your_segment_key"
}

// Use the same config everywhere
Netfunnel.nfStart(
projectKey = PROJECT_KEY,
segmentKey = SEGMENT_KEY,
callback = basicControlCallback,
activity = requireActivity()
)

Netfunnel.nfStop(
projectKey = PROJECT_KEY,
segmentKey = SEGMENT_KEY,
completeCallback = completeCallback
)

Benefits:

  • Easy to update keys across your entire app
  • Reduces copy-paste errors
  • Single source of truth for configuration

Robust Error Handling Strategy

// Why onError executes business logic but onNetworkError doesn't:

// onError (Status Code 500) - Server Error
override fun onError(statusCode: Int, message: String) {
// Scenario: NetFUNNEL server encounters internal errors
// Strategy: Execute business logic to maintain service availability
// Rationale: Server errors are typically temporary and shouldn't block user access
// Result: Robust service that continues even when NetFUNNEL has issues
businessLogic()
}

// onNetworkError (Status Code 1001, 1002) - Network Issues
override fun onNetworkError(statusCode: Int, message: String) {
// Scenario: Network connectivity problems (offline, timeout)
// Strategy: Log only, don't execute business logic
// Rationale: Use useNetworkRecoveryMode = true for automatic network recovery
// Result: Users stay in waiting room during network issues and auto-resume when connectivity returns
Log.d("NetFUNNEL", "onNetworkError(statusCode=$statusCode, message='$message')")
}

Key principle: Always proceed with business logic on system errors to maintain service availability.

Network Recovery Mode Configuration

// SampleApplication.kt
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
useNetworkRecoveryMode = true // Enable automatic network recovery
)

Benefits:

  • Automatic handling of network connectivity issues
  • Users automatically resume when network returns
  • Reduces manual network error handling complexity

Always Return Keys

// Return key after successful operation
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

// Return key when fragment is fully loaded
Netfunnel.nfStop(
projectKey = PROJECT_KEY,
segmentKey = SEGMENT_KEY,
completeCallback = completeCallback
)
}

private val completeCallback = object : NetfunnelCompleteCallback() {
override fun onComplete(statusCode: Int, message: String) {
Log.d("NetFUNNEL", "Key returned: $message")
}
}

When to return keys:

  • After Fragment loads completely
  • After API calls complete
  • After business operations finish
  • Even when operations fail

Key Matching

// Start and stop must use identical keys
const val PROJECT_KEY = "your_project_key"
const val SEGMENT_KEY = "your_segment_key"

Netfunnel.nfStart(
projectKey = PROJECT_KEY,
segmentKey = SEGMENT_KEY,
callback = callback,
activity = requireActivity()
)

Netfunnel.nfStop(
projectKey = PROJECT_KEY, // Must match exactly
segmentKey = SEGMENT_KEY, // Must match exactly
completeCallback = completeCallback
)

Comprehensive Logging

// Enable debug logging in Application class
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}",
printLog = true // Enable detailed logging
)

// Filter Logcat with: package:mine NetFUNNEL

Logging benefits:

  • Easy debugging of NetFUNNEL integration issues
  • Track request/response flow
  • Monitor key return operations
  • Identify network connectivity problems

Common Issues & Troubleshooting

Waiting Room Never Appears

Symptoms: Button click works normally, no waiting room shows up

Debug Steps:

  1. Check Logcat for Android errors: adb logcat | grep -i error
  2. Verify NetFUNNEL initialization in Application class
  3. Confirm segment is activated (not deactivated) in console
  4. Check Limited Inflow is set to 0 for testing
  5. Verify Project Key and Segment Key match console exactly (case-sensitive)

Callback Never Fires

Symptoms: nfStart() called but no response received

Debug Steps:

  1. Check Logcat for NetFUNNEL logs: adb logcat | grep NetFUNNEL
  2. Verify network connectivity to NetFUNNEL servers
  3. Check if segment is activated (not deactivated)
  4. Try with Limited Inflow = 0 to force waiting room
  5. Ensure all callback methods are implemented (Android requirement)

Users Stuck in Queue

Symptoms: First user enters, but second user never gets through

Debug Steps:

  1. Check if nfStop() is being called after business logic completes
  2. Verify keys in nfStop() match nfStart() exactly
  3. Look for Android errors preventing nfStop() execution
  4. Check Logcat for [NF4] Key return attempt detected logs
  5. Verify [NF4] Sending 5004 request appears in logs

Waiting Room Shows But Never Allows Entry

Symptoms: Waiting room appears but user never gets through, even with Limited Inflow = 1

Debug Steps:

  1. Check segment status in console - ensure it's not in "Block" mode
  2. Verify Limited Inflow is set to 1 or higher
  3. Check Logcat for [NF4] Sending 5002 request (re-entry requests)
  4. Look for error responses in the NetFUNNEL logs
  5. Verify network connectivity to NetFUNNEL servers

App Crashes on NetFUNNEL Calls

Symptoms: App crashes when calling nfStart() or nfStop()

Debug Steps:

  1. Check if required imports are added: com.nf4.Netfunnel, com.nf4.NetfunnelCallback
  2. Verify NetFUNNEL is initialized in Application class
  3. Ensure all callback methods are implemented (Android interface requirement)
  4. Check if activity context is passed correctly to nfStart()
  5. Verify NetFUNNEL agent is properly installed

Key Return Fails

Symptoms: nfStop() called but key not returned

Debug Steps:

  1. Verify keys in nfStop() match nfStart() exactly (case-sensitive)
  2. Check Logcat for [NF4] Key return attempt detected message
  3. Look for [NF4] Sending 5004 request in logs
  4. Verify [NF4] Received 5004 response with code=200
  5. Ensure NetfunnelCompleteCallback is implemented

Network Recovery Issues

Symptoms: Users get stuck during network connectivity problems

Debug Steps:

  1. Verify useNetworkRecoveryMode = true in Application initialization
  2. Check network connectivity to NetFUNNEL servers
  3. Test with airplane mode on/off to simulate network issues
  4. Monitor Logcat for onNetworkError callback calls
  5. Ensure onNetworkError doesn't execute business logic (relies on recovery mode)

QA Checklist

Pre-Implementation Verification

  • Project Key / Segment Key match console exactly (reconfirm in console)
  • NetFUNNEL agent properly initialized in Application class
  • Required imports added: com.nf4.Netfunnel, com.nf4.NetfunnelCallback, com.nf4.NetfunnelCompleteCallback
  • All callback methods implemented (Android interface requirement)

Waiting Room Testing (Limited Inflow = 0)

  • With Limited Inflow = 0, waiting room WebView displays correctly
  • Waiting room shows correct details:
    • My waiting number: 1
    • Estimated Wait Time: 00:00:00 (hh:mm:ss)
    • Queue behind: 0
  • While waiting, [NF4] Sending 5002 request appears periodically in Logcat
  • [NF4] Received 5002 response shows code=201 (WAIT)

Entry Testing (Limited Inflow = 1)

  • When changing to Limited Inflow = 1, onSuccess callback fires
  • onSuccess callback executes original business logic
  • Waiting room disappears immediately upon entry
  • Navigation to target Fragment occurs successfully

Key Return Verification

  • At completion point, key return works correctly
  • [NF4] Key return attempt detected appears in Logcat
  • [NF4] Sending 5004 request occurs with HTTP 200
  • [NF4] Received 5004 response shows code=200
  • Key return happens exactly once per nfStart call
  • Key return occurs after business logic completion

Error Handling

  • Callback branching implemented for all required states:
    • onSuccess - executes original logic
    • onError - handles system errors appropriately (proceeds with business logic)
    • onNetworkError - handles network issues appropriately (logs only)
    • onBlock - handles blocked state appropriately
    • onClose - handles user cancellation appropriately
    • onContinue - handles waiting progress appropriately
  • Network recovery mode enabled in Application initialization
  • Key matching - projectKey/segmentKey identical in nfStart and nfStop
  • Comprehensive logging implemented for all callback responses

Logcat Verification

  • NetFUNNEL logs visible with package:mine NetFUNNEL filter
  • Initialization successful message appears
  • Initial entry detected message appears on button click
  • Loading the virtual room message appears
  • Key return attempt detected message appears
  • Key Return Successful message appears in complete callback