Quickstart
Get your NetFUNNEL 4 Android Agent up and running in 5-10 minutes with this quickstart guide.
What you can do with this guide
- Code-based Integration: Apply traffic control by calling NetFUNNEL functions in your Android code
- Basic Control: Limit entry speed for activities, button clicks, and API calls
- Section Control: Control concurrent users within specific application sections
Not sure which control type to use? Check out the Integration Methods Overview to compare Basic Control and Section Control approaches and find the best fit for your use case.
Prerequisites
- NetFUNNEL console access
- Android Studio environment
- Basic understanding of Android development (Java/Kotlin)
- Android API Level 22 (Lollipop 5.1) or higher
Need a basic project to practice with? Check out our Sample Projects which include an Android Application (Single Activity) template ready for NetFUNNEL SDK integration practice.
Step 1: Install SDK & Initialize Agent
1.1 Download SDK from NetFUNNEL Console
- Log in to your NetFUNNEL console
- Navigate to Agent → Mobile Agent → Android
- Download the ZIP file:
netfunnel-android-agent-{{version}}.zip - Extract to get AAR files:
netfunnel-android-agent-debug-{{version}}.aar(development)netfunnel-android-agent-release-{{version}}.aar(production)
1.2 Add Dependencies
1. Place AAR files:
- Create
app/libs/directory - Copy AAR files to
app/libs/
2. Configure app/build.gradle:
- Kotlin DSL (build.gradle.kts)
- Groovy DSL (build.gradle)
dependencies {
// NetFUNNEL Android Agent
implementation(files("libs/netfunnel-android-agent-debug-{{version}}.aar"))
// External dependencies
val ktorVersion = "2.3.12"
val serializationVersion = "1.6.3"
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-serialization-gson:$ktorVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
}
android {
compileSdk = 34
defaultConfig {
minSdk = 22
targetSdk = 34
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
// NetFUNNEL Android Agent
implementation files("libs/netfunnel-android-agent-debug-{{version}}.aar")
// External dependencies
implementation "io.ktor:ktor-client-core:2.3.12"
implementation "io.ktor:ktor-client-okhttp:2.3.12"
implementation "io.ktor:ktor-client-content-negotiation:2.3.12"
implementation "io.ktor:ktor-serialization-gson:2.3.12"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
}
android {
compileSdk 34
defaultConfig {
minSdk 22
targetSdk 34
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
3. Add internet permission to AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
1.3 Initialize Agent
Get initialization code from NetFUNNEL console:
- Go to Agent → Mobile Agent → Android
- Copy the initialization code with your actual client ID
Add to your Application class:
Initialize in Application.onCreate() before super.onCreate(). Missing this step = bypass mode (no protection).
- Kotlin
- Java
class YourAppNameApplication : Application() {
override fun onCreate() {
super.onCreate()
Netfunnel.initialize(
clientId = "{{CLIENT_ID}}"
)
}
}
public class YourAppNameApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Netfunnel.INSTANCE.initialize(
"{{CLIENT_ID}}"
);
}
}
Register Application class in AndroidManifest.xml:
<application android:name=".YourAppNameApplication">
<!-- Your activities -->
</application>
Replace the example client ID with your actual client ID from the console.
Step 2: Choose Your Control Type
Option A: Basic Control (5 minutes)
Best for: Activity entry, button clicks, API calls
- Add the SDK to your project (see Installation & Initialization)
- Create a segment in NetFUNNEL console:
- Go to
Projects→Segments→Create Segment - Choose Basic Control
- Set Limited Inflow to
0(for testing)
- Go to
- Add this code to your activity:
- Kotlin
- Java
import com.nf4.Netfunnel
import com.nf4.NetfunnelCallback
import com.nf4.NetfunnelCompleteCallback
// When user enters an activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Netfunnel.nfStart("{{PROJECT_KEY}}", "{{SEGMENT_KEY}}", callback, this)
}
private val callback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
// User can proceed - run your original logic
setupUI()
}
override fun onError(statusCode: Int, message: String) {
// System error - proceed with original logic for service availability
setupUI()
}
override fun onNetworkError(statusCode: Int, message: String) {
// Network error - log only, rely on network recovery mode
Log.d("NetFUNNEL", "Network error: $message")
}
override fun onBlock(statusCode: Int, message: String) {
// User is blocked - show appropriate message
Log.d("NetFUNNEL", "User blocked: $message")
}
override fun onClose(statusCode: Int, message: String) {
// User closed waiting room - handle appropriately
Log.d("NetFUNNEL", "User closed waiting room: $message")
}
override fun onContinue(
statusCode: Int,
message: String,
aheadWait: Int,
behindWait: Int,
waitTime: String,
progressRate: Int
) {
Log.d("NetFUNNEL", "Continue: $message, waitTime: $waitTime")
}
}
// Return key when user leaves
override fun onDestroy() {
super.onDestroy()
Netfunnel.nfStop("{{PROJECT_KEY}}", "{{SEGMENT_KEY}}", completeCallback)
}
import com.nf4.Netfunnel;
import com.nf4.NetfunnelCallback;
import com.nf4.NetfunnelCompleteCallback;
import androidx.annotation.NonNull;
// When user enters an activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Netfunnel.INSTANCE.nfStart("{{PROJECT_KEY}}", "{{SEGMENT_KEY}}", callback, this);
}
private final NetfunnelCallback callback = new NetfunnelCallback() {
@Override
public void onSuccess(int statusCode, @NonNull String message) {
// User can proceed - run your original logic
setupUI();
}
@Override
public void onError(int statusCode, @NonNull String message) {
// System error - proceed with original logic for service availability
setupUI();
}
@Override
public void onNetworkError(int statusCode, @NonNull String message) {
// Network error - log only, rely on network recovery mode
Log.d("NetFUNNEL", "Network error: " + message);
}
@Override
public void onBlock(int statusCode, @NonNull String message) {
// User is blocked - show appropriate message
Log.d("NetFUNNEL", "User blocked: " + message);
}
@Override
public void onClose(int statusCode, @NonNull String message) {
// User closed waiting room - handle appropriately
Log.d("NetFUNNEL", "User closed waiting room: " + message);
}
@Override
public void onContinue(int statusCode, @NonNull String message, int aheadWait, int behindWait, @NonNull String waitTime, int progressRate) {
Log.d("NetFUNNEL", "Continue: " + message + ", waitTime: " + waitTime);
}
};
private final NetfunnelCompleteCallback completeCallback = new NetfunnelCompleteCallback() {
@Override
public void onComplete(int statusCode, @NonNull String message) {
// Key return completed
Log.d("NetFUNNEL", "Key returned successfully");
}
};
// Return key when user leaves
@Override
protected void onDestroy() {
super.onDestroy();
Netfunnel.INSTANCE.nfStop("{{PROJECT_KEY}}", "{{SEGMENT_KEY}}", completeCallback);
}
Result: A waiting room appears when users enter the activity.
Option B: Section Control (10 minutes)
Best for: Multi-step processes, maintaining concurrent user limits
- Add the SDK to your project (same as Option A)
- Create a segment in NetFUNNEL console (choose Section Control)
- Add this code to your checkout/payment flow:
- Kotlin
- Java
import com.nf4.Netfunnel
import com.nf4.NetfunnelCallback
import com.nf4.NetfunnelCompleteCallback
// Start section (e.g., checkout process)
fun startCheckout() {
Netfunnel.nfStartSection("{{PROJECT_KEY}}", "{{SEGMENT_KEY}}", callback, this)
}
private val callback = object : NetfunnelCallback() {
override fun onSuccess(statusCode: Int, message: String) {
// User entered the section
showCheckoutForm()
}
override fun onError(statusCode: Int, message: String) {
// System error - proceed with original logic for service availability
showCheckoutForm()
}
override fun onNetworkError(statusCode: Int, message: String) {
// Network error - log only, rely on network recovery mode
Log.d("NetFUNNEL", "Network error: $message")
}
override fun onBlock(statusCode: Int, message: String) {
// User is blocked - show appropriate message
Log.d("NetFUNNEL", "User blocked: $message")
}
override fun onClose(statusCode: Int, message: String) {
// User closed waiting room - handle appropriately
Log.d("NetFUNNEL", "User closed waiting room: $message")
}
override fun onContinue(
statusCode: Int,
message: String,
aheadWait: Int,
behindWait: Int,
waitTime: String,
progressRate: Int
) {
Log.d("NetFUNNEL", "Continue: $message, waitTime: $waitTime")
}
}
// End section (e.g., after payment completion)
fun completeCheckout() {
// Your checkout completion logic
processPayment()
// Return key after successful completion
Netfunnel.nfStopSection("{{PROJECT_KEY}}", "{{SEGMENT_KEY}}", completeCallback)
}
import com.nf4.Netfunnel;
import com.nf4.NetfunnelCallback;
import com.nf4.NetfunnelCompleteCallback;
import androidx.annotation.NonNull;
// Start section (e.g., checkout process)
public void startCheckout() {
Netfunnel.INSTANCE.nfStartSection("{{PROJECT_KEY}}", "{{SEGMENT_KEY}}", callback, this);
}
private final NetfunnelCallback callback = new NetfunnelCallback() {
@Override
public void onSuccess(int statusCode, @NonNull String message) {
// User entered the section
showCheckoutForm();
}
@Override
public void onError(int statusCode, @NonNull String message) {
// System error - proceed with original logic for service availability
showCheckoutForm();
}
@Override
public void onNetworkError(int statusCode, @NonNull String message) {
// Network error - log only, rely on network recovery mode
Log.d("NetFUNNEL", "Network error: " + message);
}
@Override
public void onBlock(int statusCode, @NonNull String message) {
// User is blocked - show appropriate message
Log.d("NetFUNNEL", "User blocked: " + message);
}
@Override
public void onClose(int statusCode, @NonNull String message) {
// User closed waiting room - handle appropriately
Log.d("NetFUNNEL", "User closed waiting room: " + message);
}
@Override
public void onContinue(int statusCode, @NonNull String message, int aheadWait, int behindWait, @NonNull String waitTime, int progressRate) {
Log.d("NetFUNNEL", "Continue: " + message + ", waitTime: " + waitTime);
}
};
private final NetfunnelCompleteCallback completeCallback = new NetfunnelCompleteCallback() {
@Override
public void onComplete(int statusCode, @NonNull String message) {
// Key return completed
Log.d("NetFUNNEL", "Section key returned successfully");
}
};
// End section (e.g., after payment completion)
public void completeCheckout() {
// Your checkout completion logic
processPayment();
// Return key after successful completion
Netfunnel.INSTANCE.nfStopSection("{{PROJECT_KEY}}", "{{SEGMENT_KEY}}", completeCallback);
}
Result: Users wait in queue before entering the checkout section, maintaining controlled concurrency.
Step 3: Test It Works
For Basic Control:
- Set Limited Inflow to 0 in your segment (waiting room should appear)
- Check the waiting room displays correctly (shows estimated wait time)
- Set Limited Inflow to 1 (should enter immediately)
- Verify key return in logs or network monitoring
For Section Control:
- Set Limited Inflow to 0 in your segment (waiting room should appear)
- Check the waiting room displays correctly (no estimated wait time shown)
- Set Limited Inflow to 1 (should enter section immediately)
- Navigate through section (Section1 → Section2 → End)
- Verify key timeout extension in logs (look for 5003 requests)
- Verify key return when section completes
Need Help?
- Troubleshooting: Common issues and solutions
- Check the Android logs for NetFUNNEL messages (enable
printLog = true) - Verify your project/segment keys match the console exactly