SfSkills Domains Docs GitHub

Home / apex / einstein-activity-capture-api

einstein-activity-capture-api

Use when querying Einstein Activity Capture (EAC) activity metrics, accessing synced email and event data via Apex, reporting on captured activities, or understanding EAC's read-only API surface and SOQL limits. Triggers: 'ActivityMetric SOQL', 'EAC data not in reports', 'UnifiedActivity query', 'query synced emails from EAC', 'activity capture SOQL returns no rows'. NOT for email template design or email deliverability configuration. NOT for enabling, configuring, or troubleshooting EAC in Setup — use admin/einstein-activity-capture-setup.

Open the skill folder on GitHub


Einstein Activity Capture API

Use this skill when an org uses Einstein Activity Capture to sync emails and calendar events from Gmail or Outlook, and a developer needs to read that synced data programmatically, query activity metrics, or understand why EAC records are invisible to standard SOQL, triggers, and reports — or why legacy Activity Metrics fields suddenly return null.


Before Starting

Gather this context before working on anything in this domain:


Core Concepts

EAC Data Lives Outside Standard Salesforce Storage (Legacy EAC)

Before Sync Email as Salesforce Activity, synced email and calendar activity resided in a Salesforce-managed external store. The Activity Timeline UI reads from that store using internal APIs, which is why the timeline looks populated even when SOQL returns nothing. Standard objects like Task, Event, and EmailMessage do not contain EAC-originated records in this model. This is not a permission issue — it is a storage architecture boundary.

Sync Email as Salesforce Activity (Summer '25+)

When enabled, captured email syncs into standard Task and EmailMessage records. Auto-captured emails appear in standard activity report types and are visible to ordinary SOQL, flows, and Apex triggers. This is the documented replacement path for legacy Activity Metrics / A360 reporting before the Spring '27 retirement.

ActivityMetric: Legacy Aggregate Surface (Retiring Spring '27)

ActivityMetric holds aggregate engagement counts per Who target (Lead or Contact). It remains queryable on legacy architectures but is on a published retirement path — fields stop populating and references return null ahead of removal. Do not start new designs on Activity Metrics; audit existing Apex, flows, and reports that reference it.

A360 Objects (Retiring Spring '27)

The Activity 360 object family retires with A360 Reports. Salesforce Help enumerates exactly six objects: UnifiedEmail, UnifiedEmailParticipant, UnifiedMeeting, UnifiedMeetingParticipant, UnifiedTask, UnifiedTaskParticipant. Existing A360 report types stop returning data when retired.

UnifiedActivity is not on that published list — it is a separately documented object representing an activity captured from EAC or another source. Treat it as neither confirmed-retiring nor confirmed-safe: it is gated on Activity 360 Reporting having been enabled before Summer '25, so verify availability in the target org rather than assuming either way, and do not start new designs on it.

EAC Reporting Constraints

EAC data is available in a dedicated Einstein Activity Capture report type in the Reports tab, separate from the standard Activities report type. The two report types cannot be joined in a single report. EmailMessage records from EAC cannot be joined with Task or Event in one report type even in Write-Back-enabled orgs because EAC EmailMessage and standard EmailMessage are logically separate. Reports on ActivityMetric are possible through the dedicated EAC report type.


Common Patterns

Querying Activity Engagement Counts via ActivityMetric (legacy EAC only)

When to use: Legacy EAC org that has not migrated, and the goal is aggregate email or meeting counts. Do not start new designs here — Activity Metrics retires Spring '27 and fields return null before removal. For Sync Email as Salesforce Activity, aggregate Task / EmailMessage instead (see Decision Guidance).

How it works: Query ActivityMetric filtering by WhoId (the Lead or Contact ID) and optionally ActivityDate. Aggregate the metric fields your use case needs. Because this is a standard SOQL query the governor limit rules apply normally.

// Fetch last 30 days of email activity counts for a set of contact IDs
Set<Id> contactIds = new Set<Id>{ '003...', '003...' };
Date cutoff = Date.today().addDays(-30);

List<ActivityMetric> metrics = [
    SELECT WhoId, ActivityDate, EmailCount, MeetingCount, EmailOpenCount
    FROM ActivityMetric
    WHERE WhoId IN :contactIds
      AND ActivityDate >= :cutoff
    ORDER BY ActivityDate DESC
];

Map<Id, Integer> emailCountByContact = new Map<Id, Integer>();
for (ActivityMetric m : metrics) {
    Integer current = emailCountByContact.containsKey(m.WhoId)
        ? emailCountByContact.get(m.WhoId) : 0;
    emailCountByContact.put(m.WhoId, current + (Integer) m.EmailCount);
}

Why not the alternative: On legacy EAC, querying Task or EmailMessage for synced data returns empty results. ActivityMetric is the interim aggregate surface there — not a long-term one. On Sync Email as Salesforce Activity, Task / EmailMessage aggregation is the replacement.

Surfacing EAC Data in a Custom Component Without Write-Back (legacy EAC only)

When to use: A Lightning Web Component needs engagement totals for a record on legacy EAC (no Sync Email architecture). Treat this as migration debt.

How it works: Build an Apex controller that queries ActivityMetric filtered to the record's related contacts or leads. Return aggregate totals to the component. Never attempt to query Task WHERE ActivityType = 'Email' expecting EAC records on legacy EAC — that returns empty.

Why not the alternative: The Activity Timeline UI already surfaces raw timeline entries. On Sync Email architecture, query Task / EmailMessage instead of ActivityMetric.


Decision Guidance

SituationRecommended ApproachReason
Need aggregate email/meeting counts for contactsNew work: aggregate Task / EmailMessage on Sync Email architecture (persist to a custom field if the score must stay queryable). Legacy interim only: ActivityMetric, with a Spring '27 migration planActivityMetric is on a published retirement path; fields return null before removal
Need individual synced email records in ApexSync Email architecture: query Task / EmailMessage. Legacy: UnifiedActivity only if already provisionedThe six A360 Unified* objects have a published Spring '27 end date; UnifiedActivity is not on that list but is gated on pre-Summer-'25 A360 enablement — verify, don't assume
Need reports on captured activityMigrate: Activities with Accounts / Activities with Opportunities on Sync Email architecture; legacy EAC report type retires Spring '27Dedicated EAC/A360 report types are on retirement path
Need to trigger Apex on an EAC email syncLegacy: scheduled batch on ActivityMetric — no trigger fires; Sync Email: ordinary Task / EmailMessage triggerArchitecture-dependent — see Security note below
Need to write to or modify EAC-synced recordsSync Email: normal Task/EmailMessage DML rules. Legacy: ActivityMetric is read-only in productionActivityMetric DML throws in production
Org is migrating to Sync Email as Salesforce ActivityAudit Activity Metrics / A360 references; validate Task/EmailMessage SOQL before cutoverRetirement is Spring '27; nulls precede hard removal

Security note for trigger-driven Sync Email designs

The sharing declaration on a trigger is fixed; the outcome of each database operation is not. Do not treat these as two independent axes.

Set the access mode explicitly on every query in the trigger and its handler. This is not "triggers always run in system mode", and it is not "sharing and access mode are independent."


Step-by-step instructions for an AI agent or practitioner working on this task:

  1. Confirm EAC storage architecture — legacy external store vs Sync Email as Salesforce Activity. Check EAC settings / admin skill; this determines every SOQL and trigger decision.
  2. Audit retirement exposure — search Apex, flows, and reports for Activity Metrics fields, A360 / Unified* objects, and Recommended Connections. Run scripts/check_einstein_activity_capture_api.py.
  3. Identify required data shape — aggregate (legacy ActivityMetric, retiring) vs individual records (Task / EmailMessage on Sync Email architecture).
  4. Write and test SOQL against the confirmed surface — never assume Task/EmailMessage contain EAC data on legacy EAC; never assume ActivityMetric is a long-term surface on Sync Email orgs.
  5. Guard against empty results and null metrics — unconnected accounts yield no rows; retiring Activity Metrics yields null without exceptions.
  6. Validate in an org with EAC connected accounts — sandboxes often lack live connections.
  7. Document architecture assumption — comment which EAC model the code targets.

Review Checklist

Run through these before marking work in this area complete:


Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

  1. Activity Timeline looks populated but SOQL returns nothing — The timeline UI reads from the EAC external store using internal APIs. SOQL against Task/Event/EmailMessage returns zero EAC rows in standard orgs. These are separate data paths.
  2. ActivityMetric is populated per connected account user only — Users who have not connected a Gmail or Outlook account have no ActivityMetric rows. Bulk queries across an entire org will silently skip unconnected users.
  3. EAC report types cannot be joined with standard Activities — EmailMessage from EAC and standard EmailMessage records live in separate report type families. Attempting to combine them in one report is not supported.
  4. Sandbox EAC behavior does not match production — Sandboxes do not replicate EAC connected account connections. Developers testing EAC queries in sandbox with no connected accounts will always get zero rows.
  5. ActivityMetric is read-only in production; DML throws exceptions — DML on ActivityMetric is supported only in @isTest contexts for seeding test data.
  6. Activity Metrics null before retirement — fields stop populating ahead of Spring '27 removal; engagement scores built on ActivityMetric silently read as zero.

Official Sources Used


Output Artifacts

ArtifactDescription
EAC storage model determinationAssessment of whether the org uses standard EAC or Write-Back-enabled EAC
ActivityMetric query patternSOQL and Apex service code for reading aggregate engagement counts
EAC reporting guidanceRecommendation for which report type to use and what cross-joins are not possible
Review findingsIssues found in existing code that incorrectly targets Task/Event/EmailMessage for EAC data

Package files