Product analytics
Skill almasumdev/awesome-mobile-observability-agent-skills/.github/skills/analytics/product-analytics
Agent skills for logging, metrics, tracing, crash reporting, and analytics in mobile apps.
npx -y skills add almasumdev/awesome-mobile-observability-agent-skills --skill product-analyticsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Design a mobile product-analytics event taxonomy with consistent naming, governance, and a registry. Use when introducing new events or cleaning up an existing Amplitude / Mixpanel / Segment / Firebase Analytics setup.
SKILL.md
6.9 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it
Product Analytics Taxonomy
Instructions
Product analytics only pays off if events are consistently named, typed, and owned. Treat the event taxonomy as a schema: reviewed, versioned, and enforced.
1. Event Naming Convention
<object>_<action> in snake_case, past tense.
- Good:
checkout_started,payment_submitted,paywall_viewed,onboarding_step_completed. - Bad:
Click Checkout Button,paymentFlow,clicked_button_42.
Rules:
- Objects come from a fixed domain list (e.g.
checkout,paywall,onboarding,feed,profile). - Actions come from a fixed verb list (
viewed,started,completed,submitted,failed,dismissed,tapped). - No event for "user did something general" -- always tie to an object.
2. Standard Properties
Every event carries a standard envelope:
| Property | Type | Notes |
|---|---|---|
event_id | uuid | generated client-side, for idempotency |
event_time | iso-ts | wall clock; server-side also stamps ingest time |
app_version | string | 4.12.0+4120 |
platform | enum | ios / android / flutter-ios / ... |
os_version | string | major.minor only |
device_class | enum | low / mid / high |
locale | string | en-US |
session_id | string | rotated on sign-out / new cold start |
user_id_hash | string | optional, only after auth |
experiment_buckets | map | { "paywall_v2": "variant_a" } |
consent_state | enum | granted / denied / not_requested |
Analytics SDKs (Amplitude, Mixpanel, Segment, Firebase Analytics) provide hooks to set these as user / super properties.
3. Event-Specific Properties
- Primitives only (string, number, boolean). No nested objects.
- Enums must be documented; a new enum value requires a registry update.
*_idfields must be hashed if they can identify a person; raw ids only for non-PII objects (product id, article id).- Include
source(home,search,deeplink) so funnels can differentiate entry points.
Example:
{
"event": "checkout_started",
"properties": {
"cart_value_cents": 2599,
"currency": "USD",
"item_count": 3,
"source": "cart",
"shipping_method": "standard"
}
}
4. Kotlin Wrapper
object Analytics {
fun track(event: AnalyticsEvent) {
if (Consent.current == Consent.Denied) return
val envelope = StandardEnvelope.current()
mixpanel.track(event.name, JSONObject(envelope + event.properties + redactedEnum(event)))
}
}
sealed class AnalyticsEvent(val name: String, val properties: Map<String, Any?>) {
class CheckoutStarted(cartValueCents: Int, currency: String, itemCount: Int, source: Source)
: AnalyticsEvent("checkout_started", mapOf(
"cart_value_cents" to cartValueCents,
"currency" to currency,
"item_count" to itemCount,
"source" to source.wire
))
}
Sealed classes prevent typos; the registry equals the set of subclasses.
5. Swift Wrapper
enum AnalyticsEvent {
case checkoutStarted(cartValueCents: Int, currency: String, itemCount: Int, source: Source)
var name: String {
switch self {
case .checkoutStarted: return "checkout_started"
}
}
var properties: [String: Any] {
switch self {
case let .checkoutStarted(v, c, n, s):
return ["cart_value_cents": v, "currency": c, "item_count": n, "source": s.rawValue]
}
}
}
6. Dart Wrapper (Flutter)
sealed class AnalyticsEvent {
String get name;
Map<String, Object?> get properties;
}
class CheckoutStarted extends AnalyticsEvent {
CheckoutStarted({required this.cartValueCents, required this.currency,
required this.itemCount, required this.source});
final int cartValueCents;
final String currency;
final int itemCount;
final Source source;
@override String get name => 'checkout_started';
@override Map<String, Object?> get properties => {
'cart_value_cents': cartValueCents,
'currency': currency,
'item_count': itemCount,
'source': source.wire,
};
}
7. TypeScript Wrapper (RN)
export type AnalyticsEvent =
| { name: 'checkout_started'; properties: { cart_value_cents: number; currency: string; item_count: number; source: Source } }
| { name: 'payment_submitted'; properties: { method: PaymentMethod; outcome: Outcome } };
export function track(event: AnalyticsEvent): void {
if (consent.current === 'denied') return;
analytics.track(event.name, { ...standardEnvelope(), ...event.properties });
}
8. Governance
- Single source of truth: a
analytics-registry.yamlin the repo lists every event, every property, allowed enum values, owner team, and PII status. - Pull request gate: CI check fails if a new event lacks a registry entry or a tracking plan link.
- Retirement policy: events deprecated must stay defined in the registry for one release cycle, then be removed from both client and data warehouse views.
- Review: data / product owns the taxonomy; engineering owns the implementation.
9. Anti-Patterns
button_clickedwith abutton_nameproperty. Create separate events; it's five events, not one.- Logging raw API payloads as properties. Always extract the specific fields you need.
- Emitting
user_signed_inmultiple times per session (guard with session state). - Setting user id before consent is granted.
10. Validation
- Unit test each wrapper: event names match the registry, enum values are exhaustive.
- A lint script parses
analytics-registry.yamland the source, failing if a wrapper emits an unregistered property. - Schema validation on ingest (see
event-schemas).
Checklist
- Events follow
<object>_<action>past-tense snake_case. - Standard envelope (version, platform, device class, consent) is attached on every event.
- A typed wrapper per platform enforces naming and property types.
-
analytics-registry.yamlexists and CI fails on drift. - Owners are assigned per event; retirement policy is documented.
- Consent state gates all tracking calls.
- Unit tests enforce registry-code consistency.