> ## Documentation Index
> Fetch the complete documentation index at: https://docs.permutive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Properties

> Structure and validate event metadata

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.

<CardGroup cols={3}>
  <Card title="Basic Usage" href="#creating-properties" icon="code" />

  <Card title="Supported Types" href="#supported-types" icon="list" />

  <Card title="Enrichment" href="#event-enrichment" icon="wand-magic-sparkles" />
</CardGroup>

## Creating Properties

`EventProperties` wraps a dictionary with type validation. Invalid types throw an exception on construction.

<CodeGroup>
  ```swift Swift theme={"dark"}
  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)")
  }
  ```

  ```objectivec Objective-C theme={"dark"}
  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];
  ```
</CodeGroup>

## Supported Types

`EventProperties` supports the following value types:

| Type          | Swift             | Objective-C                | Example      |
| ------------- | ----------------- | -------------------------- | ------------ |
| String        | `String`          | `NSString`                 | `"sports"`   |
| Integer       | `Int`             | `NSNumber`                 | `42`         |
| Float         | `Float`, `Double` | `NSNumber`                 | `3.14`       |
| Boolean       | `Bool`            | `NSNumber`                 | `true`       |
| Date          | `Date`            | `NSDate`                   | `Date()`     |
| Nested Object | `EventProperties` | `PermutiveEventProperties` | See below    |
| Array         | `[T]`             | `NSArray`                  | `["a", "b"]` |

### Nested Objects

<CodeGroup>
  ```swift Swift theme={"dark"}
  let author = try EventProperties([
      "name": "Jane Smith",
      "id": "author_123"
  ])

  let properties = try EventProperties([
      "title": "Article Title",
      "author": author  // Nested EventProperties
  ])
  ```

  ```objectivec Objective-C theme={"dark"}
  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];
  ```
</CodeGroup>

### Arrays

<CodeGroup>
  ```swift Swift theme={"dark"}
  let properties = try EventProperties([
      "tags": ["technology", "mobile", "ios"],
      "category_ids": [1, 2, 3],
      "featured": true
  ])
  ```

  ```objectivec Objective-C theme={"dark"}
  PermutiveEventProperties *properties = [[PermutiveEventProperties alloc]
      init:@{
          @"tags": @[@"technology", @"mobile", @"ios"],
          @"category_ids": @[@1, @2, @3],
          @"featured": @YES
      }
      error:nil];
  ```
</CodeGroup>

## Event Enrichment

Events can be enriched with server-side data using special property values:

### Available Enrichment Values

| Value                                           | Description               |
| ----------------------------------------------- | ------------------------- |
| `EventProperties.geoInfoValue`                  | Geographic location data  |
| `EventProperties.ispInfoValue`                  | ISP information           |
| `EventProperties.ipHashInfoValue`               | Hashed IP address         |
| `EventProperties.alchemyConceptsValue`          | Watson NLU concepts       |
| `EventProperties.alchemyEntitiesValue`          | Watson NLU entities       |
| `EventProperties.alchemyKeywordsValue`          | Watson NLU keywords       |
| `EventProperties.alchemyTaxonomyValue`          | Watson NLU taxonomy       |
| `EventProperties.alchemyDocumentEmotionValue`   | Watson document emotion   |
| `EventProperties.alchemyDocumentSentimentValue` | Watson document sentiment |
| `EventProperties.alchemyTaxonomyLabelsValue`    | Watson taxonomy labels    |
| `EventProperties.alchemyEntityNamesValue`       | Watson entity names       |

### Location and ISP Enrichment

<CodeGroup>
  ```swift Swift theme={"dark"}
  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)")
  }
  ```

  ```objectivec Objective-C theme={"dark"}
  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];
  ```
</CodeGroup>

### Watson Content Analysis (Standard Cohorts)

For Standard Cohorts support, include Watson taxonomy labels:

<CodeGroup>
  ```swift Swift theme={"dark"}
  // 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
  )
  ```

  ```objectivec Objective-C theme={"dark"}
  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];
  ```
</CodeGroup>

<Info>
  **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.
</Info>

## Schema Validation

<Warning>
  Event properties **must match** the schema defined in your Permutive dashboard. Mismatches result in event rejection.
</Warning>

### Common Schema Errors

Enable debug logging to see schema validation errors:

```swift theme={"dark"}
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

<Tabs>
  <Tab title="Valid Names">
    ```swift theme={"dark"}
    "category"          // ✅
    "word_count"        // ✅
    "articleId"         // ✅
    "section_2"         // ✅
    ```
  </Tab>

  <Tab title="Invalid Names">
    ```swift theme={"dark"}
    "word-count"        // ❌ Hyphen not allowed
    "2_section"         // ❌ Cannot start with number
    "my property"       // ❌ Spaces not allowed
    ```
  </Tab>
</Tabs>

## Using Properties with PageTracker

Properties passed to `PageTracker` are included with automatically generated events:

<CodeGroup>
  ```swift Swift theme={"dark"}
  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)
      }
  }
  ```

  ```objectivec Objective-C theme={"dark"}
  @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
  ```
</CodeGroup>

## Updating Properties Dynamically

For values that change during tracking, use the Objective-C style setter:

```swift theme={"dark"}
let properties = EventProperties()
properties.setValue("initial_value", forKey: "status")

// Later...
properties.setValue("updated_value", forKey: "status")
```

## Best Practices

<Tabs>
  <Tab title="Do">
    * 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
  </Tab>

  <Tab title="Don't">
    * 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)
  </Tab>
</Tabs>

## Troubleshooting

<AccordionGroup>
  <Accordion title="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
  </Accordion>

  <Accordion title="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
  </Accordion>

  <Accordion title="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
  </Accordion>
</AccordionGroup>

## Related Documentation

<CardGroup cols={2}>
  <Card title="Page Tracking" icon="file" href="/sdks/mobile/ios/features/page-tracking">
    Using properties with PageTracker
  </Card>

  <Card title="Event Tracking" icon="bolt" href="/sdks/mobile/ios/features/event-tracking">
    Tracking custom events
  </Card>

  <Card title="Contextual Data" icon="bullseye" href="/sdks/mobile/ios/core-concepts/contextual-data">
    Content-based segmentation
  </Card>

  <Card title="Issues" icon="triangle-exclamation" href="/sdks/mobile/ios/troubleshooting/common-errors">
    Common problems and solutions
  </Card>
</CardGroup>
