Skip to content

Data Collection Custom Rules

View

Requires enabling the configuration FTRUMConfig.enableTraceUserView = YES.

rumConfig.viewTrackingHandler = [CustomViewTracker new];

#import "FTDefaultUIKitViewTrackingHandler.h"

// Protocol implementation example
@interface CustomViewTracker : NSObject <FTUIKitViewTrackingHandler>
// Only add when SDK's default view collection rules are needed
@property (nonatomic, strong) FTDefaultUIKitViewTrackingHandler defaultHandler;
@end

@implementation CustomViewTracker

// Only add when SDK's default view collection rules are needed
-(FTDefaultUIKitViewTrackingHandler *)defaultHandler{
    if (!_defaultHandler) {
        _defaultHandler = [FTDefaultUIKitViewTrackingHandler new];
    }
    return _defaultHandler;
}

- (FTRUMView *)rumViewForViewController:(UIViewController *)viewController {
    // Exact match by class name
    if ([viewController isKindOfClass:[HomeViewController class]]) {
        return [[FTRUMView alloc] initWithViewName:@"main_home" property:@{@"page_type": @"home"}];
    }
    // Filter by prefix
    else if ([NSStringFromClass([viewController class]) hasPrefix:@"FT"]) {
        return [[FTRUMView alloc] initWithViewName:[NSString stringWithFormat:@"ft_%@", NSStringFromClass([viewController class])] property:nil];
    }
    // Set by accessibilityLabel
    else if (viewController.view.accessibilityLabel) {
        return [[FTRUMView alloc] initWithViewName:viewController.view.accessibilityLabel property:nil];
    }
    // After customizing some pages, use SDK's default collection rules for the remaining pages (return the result of the default handler)
    return [self.defaultHandler rumViewForViewController:viewController];

    // Return nil directly to skip tracking
    return nil;
}
@end
rumConfig.viewTrackingHandler = CustomViewTracker()

class CustomViewTracker: NSObject, FTUIKitViewTrackingHandler {

    // Only keep this property when SDK's default view collection rules are needed
    lazy var defaultHandler: FTDefaultUIKitViewTrackingHandler = {
        FTDefaultUIKitViewTrackingHandler() 
    }()

    func rumView(for viewController: UIViewController) -> FTRUMView? {
        // Exact match by class name
        if viewController is HomeViewController {
            let properties: [String: Any] = ["page_type": "home"]
            return FTRUMView(viewName: "main_home", property: properties)
        }

        // Filter by class name prefix
        let vcClassName = String(describing: type(of: viewController))
        if vcClassName.hasPrefix("FT") {
            let viewName = "ft_\(vcClassName)"
            return FTRUMView(viewName: viewName, property: nil)
        }

        // Set by accessibilityLabel
        if let accessibilityLabel = viewController.view.accessibilityLabel, !accessibilityLabel.isEmpty {
            return FTRUMView(viewName: accessibilityLabel, property: nil)
        }

        // After customizing some pages, use SDK's default collection rules for the remaining pages (return the result of the default handler)
        return defaultHandler.rumView(for: viewController)

        // Return nil directly to skip tracking
        return nil
    }
}

Action

Requires enabling the configuration FTRUMConfig.enableTraceUserAction = YES.

rumConfig.actionTrackingHandler = [CustomActionTracker new];

#import "FTDefaultActionTrackingHandler.h"

// Protocol implementation example
// In iOS environment, must conform to the `FTUIPressRUMActionsHandler` protocol
// In tvOS environment, must conform to the `FTUITouchRUMActionsHandler` protocol.
@interface CustomActionTracker : NSObject <FTUIPressRUMActionsHandler,FTUITouchRUMActionsHandler>
// Only add when SDK's default Action collection rules are needed
@property (nonatomic, strong) FTDefaultActionTrackingHandler defaultHandler;
@end
@implementation CustomActionTracker

// Only add when SDK's default Action collection rules are needed
-(FTDefaultActionTrackingHandler *)defaultHandler{
    if (!_defaultHandler) {
        _defaultHandler = [FTDefaultActionTrackingHandler new];
    }
    return _defaultHandler;
}

// Protocol method required for both iOS and tvOS
- (nullable FTRUMAction *)rumLaunchActionWithLaunchType:(FTLaunchType)type {
    if(type == FTLaunchCold){
      return [[FTRUMAction alloc]initWithActionName:@"cold"];
    }
    // Return nil to skip tracking
    return nil;
}

// Protocol method required for iOS environment
-(nullable FTRUMAction *)rumActionWithTargetView:(UIView *)targetView{
    if (view.accessibilityIdentifier){
       return [[FTRUMAction alloc] initWithActionName:view.accessibilityIdentifier];
    }

     // After customizing some Actions, use SDK's default collection rules for the remaining ones (return the result of the default handler)
    return [self.defaultHandler rumActionWithTargetView:targetView];

    // Return nil to skip tracking
    return nil;
}
// Protocol method required for tvOS environment
- (nullable FTRUMAction *)rumActionWithPressType:(UIPressType)type targetView:(UIView *)targetView{
    if (type == UIPressTypeSelect && view.accessibilityIdentifier){
       return [[FTRUMAction alloc] initWithActionName:view.accessibilityIdentifier];
    }

    // After customizing some Actions, use SDK's default collection rules for the remaining ones (return the result of the default handler)
    return [self.defaultHandler rumActionWithPressType:type targetView:targetView];

        // Return nil to skip tracking
    return nil;
}
@end
rumConfig.actionTrackingHandler = CustomActionTracker()

// Protocol implementation example
// In iOS environment, must conform to the `FTUIPressRUMActionsHandler` protocol
// In tvOS environment, must conform to the `FTUITouchRUMActionsHandler` protocol.
class CustomActionTracker: NSObject, FTUIPressRUMActionsHandler, FTUITouchRUMActionsHandler {

    // Only add when SDK's default Action collection rules are needed
    lazy var defaultHandler: FTDefaultActionTrackingHandler = {
        FTDefaultActionTrackingHandler()
    }()

    // Protocol method required for both iOS and tvOS
    func rumLaunchAction(with type: FTLaunchType) -> FTRUMAction? {
        if type == .cold {
            return FTRUMAction(actionName: "cold")
        }
        // Return nil to skip tracking
        return nil
    }

    // Protocol method required for iOS environment
    func rumAction(withTargetView targetView: UIView) -> FTRUMAction? {
        if let identifier = targetView.accessibilityIdentifier {
            return FTRUMAction(actionName: identifier)
        }

        // After customizing some Actions, use SDK's default collection rules for the remaining ones (return the result of the default handler)
        return defaultHandler.rumAction(withTargetView: targetView)

        // Return nil to skip tracking
        return nil 
    }

    // Protocol method required for tvOS environment
    func rumAction(with pressType: UIPress.PressType, targetView: UIView) -> FTRUMAction? {
        if pressType == .select, let identifier = targetView.accessibilityIdentifier {
            return FTRUMAction(actionName: identifier)
        }

        // After customizing some Actions, use SDK's default collection rules for the remaining ones (return the result of the default handler)        
        return defaultHandler.rumAction(with: pressType, targetView: targetView)

        // Return nil to skip tracking
        return nil
    }
}

Resource

Requires enabling the configuration FTRUMConfig.enableTraceUserResource = YES or Custom Network collection via forwarding URLSession Delegate

Filter collection based on URL

rumConfig.resourceUrlHandler = ^(NSURL *url){
        // Return YES means do not collect; Return NO means collect
        if ([url.host isEqualToString:@"example.com"]) {
            return YES;
        }
        return NO;
};
rumConfig.resourceUrlHandler = { url in 
     // Return true means do not collect; Return false means collect
     return url.host == "example.com"
}

Add custom properties

By setting a property provider closure, you can return additional properties to be attached to the RUM Resource.

For example, you might want to add the HTTP request body to the RUM Resource:

rumConfig.resourcePropertyProvider = ^NSDictionary *_Nullable(NSURLRequest *request, NSURLResponse *response,NSData *data, NSError *error) {
     NSString *body = @"";
     if (request.HTTPBody) {
        body = [[NSString alloc] initWithData:httpBody encoding:NSUTF8StringEncoding] ?: @"";
     }
     return @{@"request_body": body};
 }
rumConfig.resourcePropertyProvider = { request, response, data, error in
   let body = request.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? ""
   return ["request_body": body]
  }

Filter network errors

When a network request encounters an error, an Error data of type network_error is generated in RUM. Some URLSession local errors, like task.cancel, are normal logic within the user program and are not error data. In such cases, you can use the sessionTaskErrorFilter callback for interception and filtering. Confirm interception by returning YES, do not intercept by returning NO. After interception, RUM-Error will not collect this error.

rumConfig.sessionTaskErrorFilter = ^BOOL(NSError * _Nonnull error){
    return error.code == NSURLErrorCancelled;
}; 
rumConfig.sessionTaskErrorFilter = { error in
   return (error as? URLError)?.code == .cancelled
}