Pitch deck tracking
The same machinery pointed at a document instead of a website. Built for the HLD Sentinel investor deck, and available for any hosted deck or proposal where the question is not "how many people opened it" but "did this person read it, and where did they stop".
Why it is separate
A deck is one HTML page. Every slide change happens in the browser, so request logs show a single hit and tell you nothing. A deck also has a fixed slide count and a named audience, where a website has open-ended URLs and anonymous visitors — which is why slides are tracked by number and sessions can be labelled by recipient.
Per-slide reach
The number worth reading is reach-through: how far each viewer got before they stopped. A deck where everyone reaches slide four and nobody reaches slide six has a problem on slide five, and no amount of aggregate open-rate says so.
| Name | Type | Required | Description |
|---|---|---|---|
| max_slide | integer | No | The furthest slide this viewer reached. |
| sessions_reached | integer | No | Per slide: how many viewers ever got this far. |
| slide_views / unique_viewers | integer | No | Entries into a slide, and how many distinct viewers produced them. The gap is revisits. |
| avg_dwell_ms | number | No | Average time on the slide, from slide exits. |
| completed | boolean | No | Reached the final slide. |
| pdf_downloaded | boolean | No | Took the PDF — usually the strongest single signal in the whole record. |
Slide heatmaps
Two layers per slide, exactly as for a web page: raw click coordinates, and a binned pointer attention grid. Positions are fractions of the slide rather than pixels, because a deck letterboxes itself into whatever viewport it lands in — a click 40% across is the same place on a laptop and a boardroom display, and 700 pixels is not.
GET /api/pitch-tracking/heatmap?deck=sentinel&slide=3
GET /api/pitch-tracking/heatmap?deck=sentinel&slide=3&mode=pointerWho, not how many
| Name | Type | Required | Description |
|---|---|---|---|
| visitor_label | string | No | From ?v= on the shared link. A session has a name before anyone has to recognise an IP address. |
| visit_number | integer | No | Which visit this is. Counted server-side, so a cleared localStorage does not reset it. |
| viewer_name / viewer_email | string | No | When the link had an email gate. Set mid-session, never inferred. |
| ip_company / ip_ptr | string | No | The organisation behind the address, from one reverse-DNS lookup per session. |
| first_advance_ms | integer | No | How long before they moved off slide one. A long pause here and a short deck is someone who opened it and left. |
| slide_revisits | integer | No | Going back to a slide is interest, and it is invisible in a page-count. |
Engagement signals
- Navigation method — keyboard, click, touch or wheel. Keyboard is a careful reader; wheel is a skim.
- Zoom level, copy, print and screenshot attempts, and the context menu.
- Active time against wall-clock time, so a deck left open on a second monitor is not counted as reading.
- Full-screen and overview-mode entries.
Bot filtering matters more here
Access
Deck analytics are read through /api/pitch-tracking/analytics and are restricted to HLD global administrators — decks are internal material, so there is no client key path for them. Ask HLD to set up tracking on a deck; the dashboard lives at /pitch/tracking.