Skip to main content

UIKit Tap Instrumentation

Generates: Events (Log Records)

Automatically captures user taps in UIKit apps and emits app.widget.click events with touch coordinates, element identity, and rage-click detection.

Setup

UIKit Tap instrumentations is enabled and configured from the Pulse dashboard — it cannot be enabled from initialize(). The remote config controls:

SettingDescription
captureContextWhether to extract a human-readable label (app.click.context) from the tapped view
Rage click — time windowSliding window (ms) in which taps are counted for rage detection
Rage click — thresholdNumber of taps within the window and radius that triggers a rage event
Rage click — radiusRadius (pt) within which taps count as targeting the same element

Tap Target Detection

After a touch ends, the SDK walks from the hit view up the superview chain and attributes the tap to a semantic target — the element that best represents user intent (for example standard controls, table/collection cells, views exposed as interactive in accessibility, and common discrete gesture targets). Scroll views are not treated as the tap target, so scrolling is not misclassified as a widget click.

If no suitable target is found, the tap is recorded as a dead click (click.type = "dead").

Heuristics may change between SDK releases. For stable naming in telemetry, prefer accessibilityIdentifier (and meaningful accessibilityLabel) on the views you care about.

Generated Telemetry

Type: Log Record (Event)
Event Name: app.widget.click (set via event.name attribute — body is empty)
pulse.type: app.click

Attributes

AttributeTypeExamplePresent
click.typeString"good" / "dead"✅ Always
click.is_rageBooltrue⚠️ Rage events only
click.rage_countInt5⚠️ Rage events only
app.widget.nameString"UIButton"⚠️ Good clicks
app.widget.idString"checkout_btn"⚠️ If accessibilityIdentifier is set
app.click.contextString"label=Add to Cart"⚠️ If captureContext=true and label found
app.screen.coordinate.xInt142✅ Always
app.screen.coordinate.yInt380✅ Always
device.screen.widthInt390✅ Always
device.screen.heightInt844✅ Always
app.screen.coordinate.nxDouble0.364✅ Always
app.screen.coordinate.nyDouble0.451✅ Always

Sample Payload: Good Click

{
"body": "",
"event.name": "app.widget.click",
"attributes": {
"pulse.type": "app.click",
"click.type": "good",
"app.widget.name": "UIButton",
"app.widget.id": "checkout_btn",
"app.click.context": "label=Checkout",
"app.screen.coordinate.x": 142,
"app.screen.coordinate.y": 380,
"device.screen.width": 390,
"device.screen.height": 844,
"app.screen.coordinate.nx": 0.364,
"app.screen.coordinate.ny": 0.451,
"session.id": "f40364c92b85ec0c19c35a65be42b97f",
"screen.name": "CartViewController"
}
}

Sample Payload: Rage Click

{
"body": "",
"event.name": "app.widget.click",
"attributes": {
"pulse.type": "app.click",
"click.type": "good",
"click.is_rage": true,
"click.rage_count": 5,
"app.widget.name": "UIButton",
"app.widget.id": "submit_btn",
"app.screen.coordinate.x": 195,
"app.screen.coordinate.y": 650,
"device.screen.width": 390,
"device.screen.height": 844,
"app.screen.coordinate.nx": 0.5,
"app.screen.coordinate.ny": 0.771
}
}

Label Extraction (captureContext)

When captureContext(true), the SDK builds a human-readable label from the tapped view and nearby text (for example segment titles, UILabel text, UIButton title labels, and accessibilityLabel). A bounded scan of subviews may contribute fragments when needed.

PII safety: UITextField, UITextView, and UISearchBar never expose typed text — only their accessibilityLabel is used.

SwiftUI Limitation

This instrumentation is UIKit-only. SwiftUI apps have best-effort coverage:

  • The UIKit view tree is inspected, but the SwiftUI component hierarchy (Button vs Text vs onTapGesture) is not reflected in UIKit — you get the UIKit class names, not SwiftUI view types.