Before Sprint 8 began, Chloe B. wrote the instrumentation spec for the Resurface feature to ensure every measurable interaction . opt-in, email sent, email opened, item clicked, cadence changed, unsubscribe, and digest skipped . was tracked consistently across the client and server. The spec was written early so that Alex R. and Jess T. could instrument events during the build rather than retrofitting analytics after ship, which the team had learned from a prior feature launch was error-prone and created data gaps in the first week of measurement.
Source Notes:
Amplitude, “Event Tracking Best Practices” (amplitude.com/blog/event-tracking-best-practices) . the event naming conventions and property taxonomy used in this spec; Amplitude’s guidance on using snake_case naming, consistent property types, and separating user properties from event properties informed the structure.
Segment, “Analytics Academy: Tracking Plan” (segment.com/academy/collecting-data/naming-conventions-for-clean-data/) . the tracking plan methodology that influenced the event inventory format; Segment’s emphasis on a centralized tracking plan document as the single source of truth for all analytics events shaped the document’s role in the development workflow.
GDPR Article 6, “Lawfulness of Processing” (gdpr-info.eu/art-6-gdpr/) . the legal basis for processing analytics data in the context of the Resurface feature; the consent and legitimate interest considerations referenced in the PII & Privacy section are drawn from GDPR Article 6.
User taps “Enable Digest” on the home screen card OR toggles the Resurface Digest setting on in Settings > Notifications
Description
Records the moment a user enables the Resurface digest. Fires once per opt-in action; if a user unsubscribes and re-subscribes, a new opt-in event fires.
Resend webhook delivers an “opened” event for a digest email
Description
Records that the user (or their email client) opened the digest email. Caveat: Apple Mail Privacy Protection pre-loads tracking pixels, inflating open rates for Apple Mail users. This event is logged for completeness but is NOT used as a primary or secondary metric.
User clicks an item link in the digest email, hitting the /r/{digest_id}/{item_id} redirect endpoint
Description
Records each item click from the digest. This is the core engagement event and the basis for the email CTR metric. Fired server-side by the click redirect endpoint.
Initialization: Client-side SDK must be initialized before the home screen renders to ensure variant assignment is available for the opt-in card display logic
Client-side events fire immediately on user interaction (no batching delay)
Server-side events (digest_sent, digest_skipped) fire synchronously within the cron job after each user’s digest is processed
item_clicked fires synchronously in the click redirect endpoint before the 302 redirect is issued (must not block the redirect; use non-blocking async send with local fallback queue)
resurface_opt_in: Enable digest from home card; verify event fires with source="home_card", correct timezone, and library_size
resurface_opt_in: Enable digest from Settings; verify event fires with source="settings"
resurface_opt_in_card_viewed: Open home screen as treatment user; verify event fires after card is visible for ≥1 second
resurface_opt_in_card_dismissed: Tap dismiss on home card; verify event fires with dismiss_count=1
resurface_digest_sent: Trigger a manual digest send for a test user; verify event fires with correct digest_id, item_count, items array, and timezone
resurface_item_clicked: Click an item in a test digest email; verify event fires with correct digest_id, item_id, item_position, relevance_score, and destination_url
resurface_unsubscribe: Click unsubscribe in a test digest email; verify event fires with correct source and days_since_opt_in
resurface_cadence_changed: Change cadence from daily to 3x/week via email footer; verify event fires with correct previous/new cadence
resurface_digest_skipped: Trigger skip condition (e.g., empty library for test user); verify event fires with correct skip_reason