Quickstart
Get your NetFUNNEL 4 iOS 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 iOS code
- Basic Control: Limit entry speed for ViewControllers, button taps, 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
- Xcode environment
- Basic understanding of iOS development (Swift/Objective-C)
- iOS 12.0 or later
Need a basic project to practice with? Check out our Sample Projects which include an iOS Application (Single ViewController) 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 → iOS
- Download the ZIP file:
netfunnel-ios-agent-4.3.2-onprem.zip - Extract the ZIP file to get the folder structure:
netfunnel-ios-agent-4.3.2-onprem/
├── netfunnel-ios-agent-debug/
│ └── netfunnel_ios.xcframework
└── netfunnel-ios-agent-release/
└── netfunnel_ios.xcframework
1.2 Add Framework to Project
1. Create Frameworks folder:
- Create
Frameworksfolder at your project root - Copy
netfunnel-ios-agent-debug/netfunnel_ios.xcframeworktoFrameworksfolder (for development)
2. Register Framework in Xcode:
- Go to Project ▸ General ▸ Frameworks, Libraries, and Embedded Content
- Click + and select Add Files…
- Select the
netfunnel_ios.xcframeworkfile - Confirm the framework appears in the list
3. Add internet permission to Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
1.3 Initialize Agent
Get initialization code from NetFUNNEL console:
- Go to Agent → Mobile Agent → iOS
- Copy the initialization code with your actual server URLs
Add to your AppDelegate:
Initialize in application(_:didFinishLaunchingWithOptions:) before calling super. Missing this step = bypass mode (no protection).
- Swift
- Objective-C
import UIKit
import Netfunnel_iOS
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Netfunnel.initialize(
clientId: "{{CLIENT_ID}}",
delegate: self
)
return true
}
}
#import <UIKit/UIKit.h>
#import <Netfunnel_iOS/Netfunnel.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[agent initializeWithClientId:@"{{CLIENT_ID}}"
delegate:self];
return YES;
}
@end
Replace the placeholder {{CLIENT_ID}} with your actual client ID from the NetFUNNEL console.
Step 2: Choose Your Control Type
Option A: Basic Control (5 minutes)
Best for: ViewController entry, button taps, 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 ViewController:
- Swift
- Objective-C
import UIKit
import Netfunnel_iOS
class ViewController: UIViewController, NetfunnelDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Start NetFUNNEL when user enters the view
Netfunnel.shared.nfStart(projectKey: "{{PROJECT_KEY}}", segmentKey: "{{SEGMENT_KEY}}")
}
// MARK: - NetfunnelDelegate Methods
func nfSuccess(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// User can proceed - run your original logic
DispatchQueue.main.async {
self.setupUI()
}
}
func nfError(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// System error - proceed with original logic for service availability
DispatchQueue.main.async {
self.setupUI()
}
}
func nfNetworkError(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// Network error - log only, rely on network recovery mode
print("NetFUNNEL Network error: \(message)")
}
func nfBlock(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// User is blocked - show appropriate message
DispatchQueue.main.async {
let alert = UIAlertController(title: "Access Blocked", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
self.present(alert, animated: true)
}
}
func nfClose(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// User closed waiting room - handle appropriately
print("NetFUNNEL User closed waiting room: \(message)")
}
func nfContinue(projectKey: String, segmentKey: String, statusCode: Int, message: String, aheadWait: Int, behindWait: Int, waitTime: String, progressRate: Int) {
print("NetFUNNEL Continue: \(message), waitTime: \(waitTime)")
}
func nfComplete(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
print("NetFUNNEL Key returned successfully")
}
// Return key when user leaves
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
Netfunnel.shared.nfStop(projectKey: "{{PROJECT_KEY}}", segmentKey: "{{SEGMENT_KEY}}")
}
private func setupUI() {
// Your original UI setup logic
}
}
#import <UIKit/UIKit.h>
#import <Netfunnel_iOS/Netfunnel.h>
#import <Netfunnel_iOS/NetfunnelDelegate.h>
@interface ViewController : UIViewController <NetfunnelDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Start NetFUNNEL when user enters the view
[[Netfunnel shared] nfStartWithProjectKey:@"{{PROJECT_KEY}}" segmentKey:@"{{SEGMENT_KEY}}"];
}
// MARK: - NetfunnelDelegate Methods
- (void)nfSuccessWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// User can proceed - run your original logic
dispatch_async(dispatch_get_main_queue(), ^{
[self setupUI];
});
}
- (void)nfErrorWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// System error - proceed with original logic for service availability
dispatch_async(dispatch_get_main_queue(), ^{
[self setupUI];
});
}
- (void)nfNetworkErrorWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// Network error - log only, rely on network recovery mode
NSLog(@"NetFUNNEL Network error: %@", message);
}
- (void)nfBlockWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// User is blocked - show appropriate message
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Access Blocked"
message:message
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
});
}
- (void)nfCloseWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// User closed waiting room - handle appropriately
NSLog(@"NetFUNNEL User closed waiting room: %@", message);
}
- (void)nfContinueWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message
aheadWait:(NSInteger)aheadWait
behindWait:(NSInteger)behindWait
waitTime:(NSString *)waitTime
progressRate:(NSInteger)progressRate {
NSLog(@"NetFUNNEL Continue: %@, waitTime: %@", message, waitTime);
}
- (void)nfCompleteWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
NSLog(@"NetFUNNEL Key returned successfully");
}
// Return key when user leaves
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[Netfunnel shared] nfStopWithProjectKey:@"{{PROJECT_KEY}}" segmentKey:@"{{SEGMENT_KEY}}"];
}
- (void)setupUI {
// Your original UI setup logic
}
@end
Result: A waiting room appears when users enter the ViewController.
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:
- Swift
- Objective-C
import UIKit
import Netfunnel_iOS
class CheckoutViewController: UIViewController, NetfunnelDelegate {
// Start section (e.g., checkout process)
func startCheckout() {
Netfunnel.shared.nfStartSection(projectKey: "{{PROJECT_KEY}}", segmentKey: "{{SEGMENT_KEY}}")
}
// MARK: - NetfunnelDelegate Methods
func nfSuccess(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// User entered the section
DispatchQueue.main.async {
self.showCheckoutForm()
}
}
func nfError(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// System error - proceed with original logic for service availability
DispatchQueue.main.async {
self.showCheckoutForm()
}
}
func nfNetworkError(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// Network error - log only, rely on network recovery mode
print("NetFUNNEL Network error: \(message)")
}
func nfBlock(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// User is blocked - show appropriate message
DispatchQueue.main.async {
let alert = UIAlertController(title: "Access Blocked", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
self.present(alert, animated: true)
}
}
func nfClose(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
// User closed waiting room - handle appropriately
print("NetFUNNEL User closed waiting room: \(message)")
}
func nfContinue(projectKey: String, segmentKey: String, statusCode: Int, message: String, aheadWait: Int, behindWait: Int, waitTime: String, progressRate: Int) {
print("NetFUNNEL Continue: \(message), waitTime: \(waitTime)")
}
func nfComplete(projectKey: String, segmentKey: String, statusCode: Int, message: String) {
print("NetFUNNEL Section key returned successfully")
}
// End section (e.g., after payment completion)
func completeCheckout() {
// Your checkout completion logic
processPayment()
// Return key after successful completion
Netfunnel.shared.nfStopSection(projectKey: "{{PROJECT_KEY}}", segmentKey: "{{SEGMENT_KEY}}")
}
private func showCheckoutForm() {
// Your checkout form setup logic
}
private func processPayment() {
// Your payment processing logic
}
}
#import <UIKit/UIKit.h>
#import <Netfunnel_iOS/Netfunnel.h>
#import <Netfunnel_iOS/NetfunnelDelegate.h>
@interface CheckoutViewController : UIViewController <NetfunnelDelegate>
@end
@implementation CheckoutViewController
// Start section (e.g., checkout process)
- (void)startCheckout {
[[Netfunnel shared] nfStartSectionWithProjectKey:@"{{PROJECT_KEY}}" segmentKey:@"{{SEGMENT_KEY}}"];
}
// MARK: - NetfunnelDelegate Methods
- (void)nfSuccessWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// User entered the section
dispatch_async(dispatch_get_main_queue(), ^{
[self showCheckoutForm];
});
}
- (void)nfErrorWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// System error - proceed with original logic for service availability
dispatch_async(dispatch_get_main_queue(), ^{
[self showCheckoutForm];
});
}
- (void)nfNetworkErrorWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// Network error - log only, rely on network recovery mode
NSLog(@"NetFUNNEL Network error: %@", message);
}
- (void)nfBlockWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// User is blocked - show appropriate message
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Access Blocked"
message:message
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
});
}
- (void)nfCloseWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
// User closed waiting room - handle appropriately
NSLog(@"NetFUNNEL User closed waiting room: %@", message);
}
- (void)nfContinueWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message
aheadWait:(NSInteger)aheadWait
behindWait:(NSInteger)behindWait
waitTime:(NSString *)waitTime
progressRate:(NSInteger)progressRate {
NSLog(@"NetFUNNEL Continue: %@, waitTime: %@", message, waitTime);
}
- (void)nfCompleteWithProjectKey:(NSString *)projectKey
segmentKey:(NSString *)segmentKey
statusCode:(NSInteger)statusCode
message:(NSString *)message {
NSLog(@"NetFUNNEL Section key returned successfully");
}
// End section (e.g., after payment completion)
- (void)completeCheckout {
// Your checkout completion logic
[self processPayment];
// Return key after successful completion
[[Netfunnel shared] nfStopSectionWithProjectKey:@"{{PROJECT_KEY}}" segmentKey:@"{{SEGMENT_KEY}}"];
}
- (void)showCheckoutForm {
// Your checkout form setup logic
}
- (void)processPayment {
// Your payment processing logic
}
@end
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 iOS logs for NetFUNNEL messages (enable
printLog = true) - Verify your project/segment keys match the console exactly