<!--
{
  "availability" : [
    "iOS: 17.0.0 -",
    "iPadOS: 17.0.0 -",
    "macCatalyst: 17.0.0 -",
    "macOS: 14.0.0 -",
    "tvOS: 17.0.0 -",
    "visionOS: 1.0.0 -",
    "watchOS: 10.0.0 -"
  ],
  "documentType" : "symbol",
  "framework" : "TipKit",
  "identifier" : "/documentation/TipKit/Tips/Event",
  "metadataVersion" : "0.1.0",
  "role" : "Structure",
  "symbol" : {
    "kind" : "Structure",
    "modules" : [
      "TipKit"
    ],
    "preciseIdentifier" : "s:6TipKit4TipsO5EventV"
  },
  "title" : "Event"
}
-->

# Event

A repeatable user-defined action.

```
struct Event<DonationInfo> where DonationInfo : Decodable, DonationInfo : Encodable, DonationInfo : Sendable
```

## Overview

Use an event when you want to track an action that can occur one or more times in your app (such as a user logging in).
Then use [`donate()`](/documentation/TipKit/Tips/Event/donate()) to donate to the event when the action occurs, increasing the event count by one.

> Note: In order to remain performant, by default events only query their most recent 1000 donations.

### Creating an event with no associated donation value

The example below creates a `landmarksAppDidOpen` event with no associated donation value and donates it anytime `ContentView` appears:

```swift
struct LandmarkTips: App {
    static let landmarksAppDidOpen = Tips.Event(id: "landmarksAppDidOpen")

    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear { Self.landmarksAppDidOpen.sendDonation() }
        }
    }
}
```

The example below creates a display rule for `LandmarkFeatureTip` based on the `landmarksAppDidOpen` event.

```swift
struct LandmarkFeatureTip: Tip {
    var rules: [Rule] {
        // Tip will only display when the landmarksAppDidOpen event has been donated 3 or more times in the last week.
        #Rule(LandmarkTips.landmarksAppDidOpen) {
            $0.donations.donatedWithin(.week).count >= 3
        }
    }
}
```

### Creating an event with an associated donation value

The example below creates a `didViewLandmarkDetail` event with an associated donation value and donates it anytime the `LandmarkDetail` appears:

```swift
struct LandmarkDetail: View {
    static let didViewLandmarkDetail = Tips.Event<DidViewLandmark>(id: "didViewLandmarkDetail")

    struct DidViewLandmark: Codable, Sendable {
        let landmarkID: Int
        let landmarkName: String
    }

    var landmark: Landmark

    var body: some View {
        ScrollView {
            MapView(coordinate: landmark.locationCoordinate)
        }
        .onAppear {
            Self.didViewLandmarkDetail.sendDonation(.init(landmarkID: landmark.id, landmarkName: landmark.name))
        }
    }
}
```

The example below creates a display rule for `LandmarkDetailTip` based on the `didViewLandmarkDetail` event.

```swift
struct LandmarkDetailTip: Tip {
    var rules: [Rule] {
        // Tip will only display when the didViewLandmarkDetail has been donated 3 or more times for landmarks not named "Wilbere Bowl".
        #Rule(LandmarkDetail.didViewLandmarkDetail) {
            $0.donations.filter({ $0.landmarkName != "Wilbere Bowl" }).count > 3
        }
    }
}
```

### Filtering an event’s donations

TipKit provides methods on `Sequence` for filtering an event’s donations within rule predicates.

Use `Swift/Sequence/donatedWithin(_:)` to filter donations by recency:

```swift
#Rule(AppEvents.didLogin) {
    $0.donations.donatedWithin(.week).count >= 3
}
```

Use `Swift/Sequence/largestSubset(groupedBy:)` and `Swift/Sequence/smallestSubset(groupedBy:)` to find the most or least frequent donation values:

```swift
#Rule(LandmarkDetail.didViewLandmarkDetail) {
    // Show tip when the most-viewed landmark has been viewed 5+ times.
    $0.donations.largestSubset(groupedBy: \.landmarkID).count >= 5
}
```

These methods can be combined to build complex eligibility conditions:

```swift
#Rule(LandmarkDetail.didViewLandmarkDetail) {
    // Show tip when the least-viewed landmark in the past month has been viewed at least twice.
    $0.donations.donatedWithin(.month).smallestSubset(groupedBy: \.landmarkID).count >= 2
}
```

## Topics

### Initializers

[`init(id:)`](/documentation/TipKit/Tips/Event/init(id:)-99edo)

Creates an event.

[`init(id:donationLimit:)`](/documentation/TipKit/Tips/Event/init(id:donationLimit:)-7tgi1)

Creates an event.

### Initializers with a donation value

[`init(id:)`](/documentation/TipKit/Tips/Event/init(id:)-3edd4)

Creates an event with an associated donation value.

[`init(id:donationLimit:)`](/documentation/TipKit/Tips/Event/init(id:donationLimit:)-1d1hy)

Creates an event with an associated donation value.

### Donations

[`Donation`](/documentation/TipKit/Tips/Event/Donation)

A repeatable user-defined action.

[`donations`](/documentation/TipKit/Tips/Event/donations)

Returns an events existing donations.

### Add Donations

[`donate()`](/documentation/TipKit/Tips/Event/donate())

Donates an event with no associated `Donation` value.

[`donate(_:)`](/documentation/TipKit/Tips/Event/donate(_:))

Donates an event along with its associated `Donation` value.

[`sendDonation(_:)`](/documentation/TipKit/Tips/Event/sendDonation(_:))

Asynchronously donates an event with no associated `Donation` value.

[`sendDonation(_:_:)`](/documentation/TipKit/Tips/Event/sendDonation(_:_:))

Asynchronously donates an event along with its associated `Donation` value.

### Delete Donations

[`deleteDonations()`](/documentation/TipKit/Tips/Event/deleteDonations())

Deletes an event’s existing donations.

### Filter Donations

## See Also

[`Rule`](/documentation/TipKit/Tips/Rule)

A condition to meet before displaying a tip.



---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)