Event properties allow you to attach metadata to events for richer segmentation and targeting. The iOS SDK uses the EventProperties class to encapsulate this data with type safety.
Creating Properties
EventProperties wraps a dictionary with type validation. Invalid types throw an exception on construction.
do {
let properties = try EventProperties ([
"category" : "sports" ,
"author" : "John Doe" ,
"published" : true ,
"word_count" : 1500
])
try Permutive. shared . track ( event : "ArticleView" , properties : properties)
} catch {
print ( "Failed to create properties: \( error ) " )
}
NSError *error = nil;
PermutiveEventProperties *properties = [[PermutiveEventProperties alloc]
init:@{
@"category": @"sports",
@"author": @"John Doe",
@"published": @YES,
@"word_count": @1500
}
error:&error];
if (error != nil) {
NSLog(@"Failed to create properties: %@", error);
return;
}
[Permutive.shared trackWithEvent:@"ArticleView" properties:properties error:&error];
Supported Types
EventProperties supports the following value types:
Type Swift Objective-C Example String StringNSString"sports"Integer IntNSNumber42Float Float, DoubleNSNumber3.14Boolean BoolNSNumbertrueDate DateNSDateDate()Nested Object EventPropertiesPermutiveEventPropertiesSee below Array [T]NSArray["a", "b"]
Nested Objects
let author = try EventProperties ([
"name" : "Jane Smith" ,
"id" : "author_123"
])
let properties = try EventProperties ([
"title" : "Article Title" ,
"author" : author // Nested EventProperties
])
PermutiveEventProperties *author = [[PermutiveEventProperties alloc]
init:@{@"name": @"Jane Smith", @"id": @"author_123"}
error:nil];
PermutiveEventProperties *properties = [[PermutiveEventProperties alloc]
init:@{@"title": @"Article Title", @"author": author}
error:nil];
Arrays
let properties = try EventProperties ([
"tags" : [ "technology" , "mobile" , "ios" ],
"category_ids" : [ 1 , 2 , 3 ],
"featured" : true
])
PermutiveEventProperties *properties = [[PermutiveEventProperties alloc]
init:@{
@"tags": @[@"technology", @"mobile", @"ios"],
@"category_ids": @[@1, @2, @3],
@"featured": @YES
}
error:nil];
Event Enrichment
Events can be enriched with server-side data using special property values:
Available Enrichment Values
Value Description EventProperties.geoInfoValueGeographic location data EventProperties.ispInfoValueISP information EventProperties.ipHashInfoValueHashed IP address EventProperties.alchemyConceptsValueWatson NLU concepts EventProperties.alchemyEntitiesValueWatson NLU entities EventProperties.alchemyKeywordsValueWatson NLU keywords EventProperties.alchemyTaxonomyValueWatson NLU taxonomy EventProperties.alchemyDocumentEmotionValueWatson document emotion EventProperties.alchemyDocumentSentimentValueWatson document sentiment EventProperties.alchemyTaxonomyLabelsValueWatson taxonomy labels EventProperties.alchemyEntityNamesValueWatson entity names
Location and ISP Enrichment
do {
let properties = try EventProperties ([
"geo_info" : EventProperties. geoInfoValue ,
"isp_info" : EventProperties. ispInfoValue ,
"form_id" : "contact_form"
])
try Permutive. shared . track ( event : "FormSubmission" , properties : properties)
} catch {
print ( "Error: \( error ) " )
}
PermutiveEventProperties *properties = [PermutiveEventProperties new];
[properties setValue:PermutiveEventProperties.geoInfoValue forKey:@"geo_info"];
[properties setValue:PermutiveEventProperties.ispInfoValue forKey:@"isp_info"];
[properties setValue:@"contact_form" forKey:@"form_id"];
NSError *error = nil;
[Permutive.shared trackWithEvent:@"FormSubmission" properties:properties error:&error];
Watson Content Analysis (Standard Cohorts)
For Standard Cohorts support, include Watson taxonomy labels:
// Create nested taxonomy structure
let urlTaxonomy = try EventProperties ([
"taxonomy_labels" : EventProperties. alchemyTaxonomyLabelsValue
])
let properties = try EventProperties ([
"classifications_watson" : urlTaxonomy
])
// Create PageTracker with these properties
let context = Context (
title : "Article Title" ,
url : URL ( string : "https://example.com/article" ),
referrer : nil
)
let pageTracker = try Permutive. shared . createPageTracker (
properties : properties,
context : context
)
NSError *error = nil;
PermutiveEventProperties *urlTaxonomy = [[PermutiveEventProperties alloc]
init:@{@"taxonomy_labels": PermutiveEventProperties.alchemyTaxonomyLabelsValue}
error:&error];
PermutiveEventProperties *properties = [[PermutiveEventProperties alloc]
init:@{@"classifications_watson": urlTaxonomy}
error:&error];
PermutiveContext *context = [[PermutiveContext alloc]
initWithTitle:@"Article Title"
url:[NSURL URLWithString:@"https://example.com/article"]
referrer:nil];
NSObject<PermutivePageTrackerProtocol> *pageTracker =
[Permutive.shared createPageTrackerWithProperties:properties
context:context
error:&error];
Standard Cohorts Requirement: For Standard Cohorts to work, both a valid URL in the Context and the classifications_watson.taxonomy_labels property must be set. Contact your Customer Success Manager (CSM) to enable this feature.
Schema Validation
Event properties must match the schema defined in your Permutive dashboard. Mismatches result in event rejection.
Common Schema Errors
Enable debug logging to see schema validation errors:
options. logModes = LogMode. all
Error messages look like:
Permutive: [error] Encountered 1 event rejection!
Permutive: [error] Schema validation failed with reason(s): [#: extraneous key [invalid_key] is not permitted]
Property Name Rules
Property names must follow these rules:
Only alphanumeric characters and underscores: [a-zA-Z0-9_]
Cannot start with a number
Case-sensitive
Valid Names
Invalid Names
"category" // ✅
"word_count" // ✅
"articleId" // ✅
"section_2" // ✅
"word-count" // ❌ Hyphen not allowed
"2_section" // ❌ Cannot start with number
"my property" // ❌ Spaces not allowed
Using Properties with PageTracker
Properties passed to PageTracker are included with automatically generated events:
class ArticleViewController : UIViewController {
private var pageTracker: PageTrackerProtocol?
override func viewDidLoad () {
super . viewDidLoad ()
let properties = try ? EventProperties ([
"category" : "technology" ,
"subcategory" : "mobile" ,
"author_id" : "author_456" ,
"premium" : true
])
let context = Context (
title : "iOS Development Guide" ,
url : URL ( string : "https://example.com/ios-guide" ),
referrer : nil
)
// Properties included with Pageview and PageViewComplete events
pageTracker = try ? Permutive. shared . createPageTracker (
properties : properties,
context : context
)
}
override func viewDidAppear ( _ animated : Bool ) {
super . viewDidAppear (animated)
try ? pageTracker?. resume ()
}
func onLinkClick ( linkName : String ) {
// Additional properties for specific events
let clickProperties = try ? EventProperties ([
"link_name" : linkName,
"position" : "header"
])
try ? pageTracker?. track ( event : "LinkClick" , properties : clickProperties)
}
}
@interface ArticleViewController ()
@property (nonatomic, strong) NSObject<PermutivePageTrackerProtocol> *pageTracker;
@end
@implementation ArticleViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSError *error = nil;
PermutiveEventProperties *properties = [[PermutiveEventProperties alloc]
init:@{
@"category": @"technology",
@"subcategory": @"mobile",
@"author_id": @"author_456",
@"premium": @YES
}
error:&error];
PermutiveContext *context = [[PermutiveContext alloc]
initWithTitle:@"iOS Development Guide"
url:[NSURL URLWithString:@"https://example.com/ios-guide"]
referrer:nil];
self.pageTracker = [Permutive.shared
createPageTrackerWithProperties:properties
context:context
error:&error];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.pageTracker resumeAndReturnError:nil];
}
- (void)onLinkClick:(NSString *)linkName {
NSError *error = nil;
PermutiveEventProperties *clickProperties = [[PermutiveEventProperties alloc]
init:@{@"link_name": linkName, @"position": @"header"}
error:&error];
[self.pageTracker trackWithEvent:@"LinkClick"
properties:clickProperties
error:&error];
}
@end
Updating Properties Dynamically
For values that change during tracking, use the Objective-C style setter:
let properties = EventProperties ()
properties. setValue ( "initial_value" , forKey : "status" )
// Later...
properties. setValue ( "updated_value" , forKey : "status" )
Best Practices
Match property names and types exactly to your schema
Use consistent property names across your app
Use meaningful, descriptive property names
Validate properties exist in your schema before deploying
Use nested properties for complex structured data
Test with debug logging enabled
Don’t include PII in event properties
Don’t use dynamic property names that aren’t in your schema
Don’t include empty or null values unnecessarily
Don’t exceed reasonable property counts (keep under 50 per event)
Don’t use very large arrays (may impact performance)
Troubleshooting
Event rejected with schema error
Problem: Console shows schema validation errors.Solutions:
Check property names match your dashboard schema exactly
Verify property types are correct (string vs int vs bool)
Remove any extra properties not in the schema
Check for typos in property names
EventProperties init throws exception
Problem: Creating EventProperties fails.Solutions:
Verify all values are supported types
Ensure no unsupported types like custom objects
Check nested EventProperties are valid
Enrichment values not working
Problem: Geo/ISP data not appearing.Solutions:
Ensure your schema includes the enrichment property
Contact support to verify enrichment is enabled
Check you’re using the correct enrichment value constant
Page Tracking Using properties with PageTracker
Event Tracking Tracking custom events
Contextual Data Content-based segmentation
Issues Common problems and solutions