Track who viewed a document
Pull view analytics for a document or link over a date range.
Three flavors of "who viewed it":
- Per-link, per-view detail — every individual view, with viewer email, country, time spent, page-by-page durations
- Per-document aggregates — totals, unique viewers, average read time across every link to that document
- Per-link aggregates — same shape, scoped to one link
- Per-dataroom aggregates — same shape, rolled up across every document inside a dataroom and every link to it
Pick the flavor that matches the question.
Per-view detail
LINK=link_abcd1234
# All views for one link
papermark views list --link "$LINK"
# This week only, JSON, just email + duration
papermark views list --link "$LINK" --json \
| jq '.data[]
| select(.viewedAt > "2026-04-18T00:00:00Z")
| {email: .viewer.email, duration}'curl "https://api.papermark.com/v1/analytics/views/$LINK?limit=100" \
-H "Authorization: Bearer $PAPERMARK_TOKEN"Returns paginated view events with full per-page breakdowns.
Required scope: analytics.read.
Who from Acme viewed the Q4 pitch deck this week, and how long did they spend?
The agent finds the link (list_links filtered by document name),
calls list_link_views, filters to this week's Acme emails, and
summarizes.
Per-document aggregates
For "how is this doc performing across every link?" — totals without per-view detail.
DOC_ID=doc_aBc123
curl "https://api.papermark.com/v1/analytics/documents/$DOC_ID" \
-H "Authorization: Bearer $PAPERMARK_TOKEN"Response:
{
"data": {
"documentId": "doc_aBc123",
"totalViews": 47,
"uniqueViewers": 12,
"averageReadTime": 184,
"lastViewedAt": "2026-04-25T08:42:11.000Z"
}
}Add ?start= and ?end= as ISO 8601 datetimes for a date range.
The CLI wraps dataroom analytics
(papermark datarooms stats <id>)
but not yet per-document or per-link analytics — call those
endpoints directly or use the MCP tool below.
How is the Q4 pitch deck performing — total views, unique viewers, average time spent?
The agent calls get_document_analytics and reads the response.
Per-dataroom aggregates
The most common dataroom question — "how is the Acme dataroom performing?" — is one CLI call:
papermark datarooms stats dr_K8mN2pQrWindow it with --since and --until (Unix milliseconds — different
from the rest of the API's ISO 8601, because dataroom stats are
backed by Tinybird):
SINCE=$(node -e "console.log(Date.now() - 7*24*60*60*1000)")
papermark datarooms stats dr_K8mN2pQr --since "$SINCE"Heads-up: this endpoint is rate-limited more aggressively than the rest of the API. Cache responses if you're polling.
For per-viewer breakdown inside a dataroom (who's been there, when):
papermark datarooms viewers dr_K8mN2pQr
papermark datarooms viewers dr_K8mN2pQr --email lead@acme.comPer-link aggregates
Same shape as per-document, scoped to one link:
curl "https://api.papermark.com/v1/analytics/links/$LINK_ID" \
-H "Authorization: Bearer $PAPERMARK_TOKEN"Use this to compare performance across multiple links to the same document (e.g., "did the Acme link or the Brand-X link get more attention?").
Page-level engagement
Per-view records include a pages array — one entry per page with
the seconds the viewer spent on it. Useful for finding the "drop-off
slide":
papermark views list --link "$LINK" --json \
| jq '[.data[].pages[]] | group_by(.page)
| map({page: .[0].page, avg_seconds: ([.[].duration] | add / length)})'Output:
[
{"page": 1, "avg_seconds": 18.4},
{"page": 2, "avg_seconds": 142.3},
{"page": 3, "avg_seconds": 4.1},
…
]A page with average duration near zero is where viewers gave up — worth rewriting.
Daily report
Cron a one-liner:
0 9 * * * papermark views list --link "$LINK" --json \
| jq -r '.data[] | select(.viewedAt > now - 86400 | todate) |
"\(.viewer.email) — \(.duration)s"' \
| mail -s "Yesterday's pitch deck views" you@example.comFor real-time notifications (every view as it happens), you'll want webhooks — coming soon. Until then, polling once a day is the right cadence.