Pendo data can include page, feature, Track Event, guide, poll, visitor, and account activity. Choose an event-level export when you need historical behavior. Do not rebuild a raw event history from aggregate report totals.
Choose Data Sync or the Aggregation API#
Pendo's current export-method guidance distinguishes:
- Data Sync for large, recurring, granular exports
- Aggregation API for smaller targeted queries and calculated data
Pendo documents Data Sync delivery to cloud storage or Snowflake and granular event exports in Avro. Availability and historical range depend on the subscription; verify them before planning.
Use Data Sync for event history. Use the Aggregation API only when the desired target is explicitly an aggregate or no granular export exists for that data.
Inspect a complete Data Sync export#
Pendo documents:
exportmanifest.json- a daily bill of materials
allevents.avro- definition files for features, pages, guides, and Track Events
- event-specific matched-event files
See Data Sync event export handling and the current schema definitions.
Process the manifest and bill of materials. Do not guess completeness from file names or load a directory while its export is still being written.
Select the target events#
Mapping worksheet:
| Pendo concept | GraphJSON target |
|---|---|
| approved Track Event | stable product event |
| tagged Feature interaction | explicit discovery or use event |
| tagged Page event | approved page_viewed event |
| guide presented or dismissed | lifecycle or messaging event |
| poll response | feedback collection with privacy review |
| raw unmatched interaction | usually exclude |
Pendo feature and page definitions act as labels over captured activity. Preserve the stable matchable ID and the definition metadata used during the export. Display names can change.
Preserve identity grains#
Keep:
- Pendo visitor ID
- Pendo account ID
- application user ID when available
- application account ID when available
- source application ID
- event ID and matchable ID
Do not use visitor email or account name as GraphJSON identity. If Pendo IDs are the only historical keys, retain them as opaque source IDs and create a reviewed mapping to application IDs.
Create deterministic event identity#
Pendo's Data Sync schema documents the fields used to form a unique event key, including event ID, matchable ID, and browser timestamp.
Create a stable target identity from the documented source key:
event_id =
"pendo:"
+ sha256(
source_application_id
+ event_id
+ matchable_id
+ browser_timestamp
)
The exact components depend on the event file and schema version. Store the mapping version and do not switch identity logic halfway through a backfill.
Choose occurrence time#
Pendo exports can contain browser and processing timestamps. Select the field that represents occurrence time for the source event, convert milliseconds to whole Unix seconds when necessary, and preserve a processing timestamp only for delay analysis.
function unixSecondsFromMillis(value) {
const milliseconds = Number(value);
if (!Number.isFinite(milliseconds)) {
throw new Error("Invalid Pendo timestamp");
}
return Math.floor(milliseconds / 1000);
}
Verify the result against events visible in the Pendo interface and across daylight-saving boundaries. Never pass milliseconds directly to GraphJSON's timestamp field.
Normalize one event#
function normalizePendoTrackEvent(row, definition) {
return {
timestamp: unixSecondsFromMillis(row.browserTimestamp),
body: {
event: definition.graphjson_event,
event_id: buildPendoEventId(row),
source: "pendo",
source_event_id: String(row.eventId),
source_matchable_id: String(row.matchableId),
pendo_visitor_id: String(row.visitorId),
pendo_account_id: String(row.accountId || ""),
user_id: row.application_user_id || null,
account_id: row.application_account_id || null,
source_application_id: String(row.applicationId),
schema_version: 1
}
};
}
Use the exact field capitalization and types in your Data Sync schema sample. The pseudocode describes the target contract; it is not a universal Avro decoder.
Preserve definition history#
Keep a snapshot:
matchable ID:
Pendo type:
Pendo display name:
rule or definition version:
source application:
GraphJSON event:
effective interval:
mapping version:
If a Page or Feature rule changes retroactively, a later export may classify historical events differently. Decide whether the migration uses:
- the latest Pendo classification
- an earlier frozen export
- a custom stable business-event definition
Document the choice beside the reconciliation results.
Handle finalized and retroactive exports#
Pendo Data Sync documentation describes recurring, finalized, and retroactive export behavior. Build ingestion around the manifest rather than assuming each calendar day is immutable after its first delivery.
For the migration:
- load a bounded one-time historical export
- load recurring updates into staging
- replace or merge by stable source identity
- wait through the documented finalization interval
- record the final high-water mark
Do not append a later finalized file as if it contained only new events.
Import through bounded batches#
Normalize Avro into a staging format such as NDJSON:
{"timestamp":1785110400,"body":{"event":"report_exported","event_id":"pendo:...","schema_version":1}}
Validate required IDs, timestamp, JSON size, and allowed field types. Send up
to 50 events per /api/bulk-log request. Keep a quarantine file with source
location and safe error reason.
Reconcile#
Compare:
- manifest files expected and loaded
- source records selected
- unique source keys
- normalized, accepted, and quarantined records
- counts by Pendo event type, GraphJSON event, application, and day
- min and max occurrence time
- visitor and account distinct counts
- selected funnels or feature-adoption metrics
Aggregate API results may not match granular event counts because their query, definition, or processing grain differs. Reconcile the migration first to the Data Sync records actually selected.
Cut over#
For future activity, prefer explicit application-owned events sent to GraphJSON. During a bounded dual-run:
- compare Pendo Track Events with GraphJSON product events
- distinguish Pendo Page and Feature rules from explicit value events
- verify user and account mapping
- identify Pendo-only guide or poll events that still need a source
- stop at an exact occurrence-time boundary
Migration checklist#
- Data Sync or Aggregation API was chosen for the required grain.
- A complete manifest and schema sample were inspected.
- Event, Page, Feature, Guide, and Poll mappings are explicit.
- Visitor, account, application, and source-event IDs remain distinct.
- Stable event identity follows the source schema.
- Millisecond timestamps are converted and verified.
- Definition metadata is snapshotted.
- Finalized and retroactive files are merged, not blindly appended.
- Raw unmatched interaction data is minimized.
- Backfill batches and quarantine respect GraphJSON limits.
- Granular source records reconcile before UI aggregates.
- Live cutover replaces rule-based capture with explicit events where appropriate.