Skip to main content

Why teams build this

Security and GRC leaders are increasingly asked to show that the trust center is doing commercial work. The question from leadership is usually some version of “which accounts are reviewing us, and what are they reading?” Answering it in a spreadsheet gets stale within a week. Answering it in Hex lets you join trust center activity to the CRM and pipeline data you already have there, so document engagement sits next to deal stage and account owner.

What one row looks like

The dataset this guide produces has one row per interaction: No cell is ever null. Rows carry unattributed and an empty email when a visit has not been tied to a company or a person, and two boolean columns let you filter to the level of attribution you want. See how much of the activity is identified. event_type currently returns one of DOCUMENT_VIEWED, DOCUMENT_DOWNLOADED, or LINK_DOCUMENT_OPENED. Treat it as a passthrough column so new activity types flow into your dashboard without a code change.

Before you start

Bind the key to a service account. A scheduled Hex refresh then keeps working when the person who created the key changes roles or leaves the company. See service accounts.

Step 1: Create an API key

1

Create the service account first

Go to Settings → Service accounts and create one named something like Hex reporting. Set its role to Admin, because the per-document endpoint this guide uses is admin only and the role selector starts on User.Do this before opening API settings. The Owner dropdown on the key dialog lists the service accounts that already exist, so it offers only Yourself until one is there to pick. Full walkthrough: service accounts.
2

Open API settings

Go to Settings → API. This page is visible to admins.
3

Create the key

Click Create API key. Give it a Name such as Hex trust center reporting, set Owner to your service account, and pick an Expiration.
4

Copy it once

The key is shown a single time and starts with wolfia-api-. Copy it before closing the dialog.

Step 2: Store the key as a Hex secret

Open the Variables sidebar in your Hex project. In the Secrets section, click +Add, choose Create project secret, and name it WOLFIA_API_KEY. Hex stores secrets in an encrypted vault and renders them as [SECRET VALUE] if anything tries to display them, so the key stays out of your notebook source and out of any published app. A secret is referenced in a Python cell by its bare name, which is why the sample below uses WOLFIA_API_KEY directly with no lookup around it.
Use a secret for the API key. Hex environment variables are read through os.environ and are stored without encryption or redaction, which makes them unsuitable for a credential.

Step 3: Build the interactions dataframe

This cell walks every document in your trust center, pulls the interaction history for each one, and returns a tidy dataframe. It requests one calendar month at a time. A single request returns at most 100 activity events, so a busy document in a wide date window would silently lose its older events. Monthly windows keep each request comfortably under that ceiling.
Assign the result to a named dataframe and Hex will make it available to downstream SQL and chart cells.

How much of the activity is identified

A trust center is a public page. Someone can read your SOC 2 before they ever tell you who they are, so every interaction falls into one of three levels of identification. The sample code labels all three so your dashboard has no blank cells, and it sets two boolean columns so you can filter deliberately. Two things follow from how this works, and both are useful:
  • An email never appears without a domain. Individual identification comes from an access request, and an access request always belongs to an account. So account_domain is always at least as complete as user_email, and it is the right column to group by for account level reporting.
  • Unidentified visits are real engagement. Dropping them understates how much your trust center is being read, which is usually the opposite of the point. Keep them in the totals and filter only when you specifically need account level attribution:
The proportion of each level varies by trust center, by how much traffic arrives from public search, and by how much of your document set sits behind an access request.

Choosing your join keys

Use document_title as the document key. Documents are grouped by title, so re-uploading a refreshed SOC 2 keeps its history in one place. The document_id you pass to the API points at the current representative version of a title and can change after a re-upload, which makes it a poor primary key for a saved dashboard. One caveat: grouping is by exact title, so SOC 2 Type 2 Report and Acme SOC 2 Type II Report count as two documents. If you have renamed a document over time, map the variants to one canonical name in your dashboard. Use account_domain as the customer key. It is the stable identifier for a visiting company and joins cleanly to the website or domain field on your CRM accounts.

Keeping the dataset fresh

A visitor can browse before they finish verifying their identity. When they do verify, their earlier activity is attributed to them and to their account, so a row that was anonymous an hour ago can gain an account_domain and a user_email.Set each scheduled run to re-pull the last 30 days and let event_id de-duplicate. Rows that gained attribution get corrected, and nothing is double counted.
event_id is unique and stable per interaction. It is the right key for an upsert into a warehouse table and for drop_duplicates in a notebook.
Run the full historical range once and write it to a table. After that, schedule a run over a trailing window only. A full backfill across many months and many documents makes a lot of requests, so keep it to a one-off.
Documents you have taken down still appear in the document list, flagged with is_deleted. Their historical interactions remain available so a trend line does not develop a hole when you retire a report.

Limits to design around

Troubleshooting

Confirm the header is X-API-Key and the value begins with wolfia-api-. A key that has been deactivated, deleted, or has passed its expiration date also returns 401. Check its status on Settings → API.
The per-document endpoint requires the Admin role. If the key is bound to a service account, raise that service account to Admin or issue the key under an admin owner.
You have exceeded the hourly or burst rate limit. Increase REQUEST_PAUSE_SECONDS, and split a large backfill across several runs.
Check the date window first. start_date and end_date are microseconds, and passing seconds or milliseconds produces a window that matches nothing. Then confirm your trust center was live during the period you asked for.
This is expected on a public trust center rather than a fault in the extract. A visitor can read a public document without identifying themselves, and a row gains an email only once someone verifies their identity, so re-pulling a trailing window fills in more of them over time.Group by account_domain for account level reporting, or filter on has_known_person when you specifically need named individuals. The three levels of identification are explained in how much of the activity is identified.
Same cause, one level up. The visit was not tied to any company, usually because the reader arrived on a public page and never requested access. The sample code labels these unattributed so nothing is silently dropped from your totals. Filter on has_known_account to exclude them from account level views.

Adapting this to other tools

Nothing here is specific to Hex beyond where the credential lives. The same requests work from any scheduler or notebook that can hold a secret and make HTTPS calls, including Databricks, Snowflake external functions, Airflow, and dbt Python models. Replace the bare WOLFIA_API_KEY reference with your platform’s own secret lookup, which on most of them is os.environ["WOLFIA_API_KEY"], and keep the rest of the code as it is.

Next steps

Trust analytics API

The full endpoint reference, including revenue attribution, active accounts, and access requests.

API overview

Authentication, rate limits, status codes, and every endpoint area.

Service accounts

Bind API keys to a non-human identity so scheduled jobs survive team changes.

Trust Center

Set up documents, branding, and access controls on the trust center itself.