Overview
Call history on macOS is stored in CallHistory.storedata, a Core Data SQLite database that records metadata for every phone call, FaceTime audio call, and FaceTime video call. Each call is a row in the ZCALLRECORD table with fields for direction, duration, answered status, call type, and participant information. Group FaceTime calls link to participants through a join table. FaceTime Links (shareable meeting URLs introduced in macOS 12 Monterey) are stored in a separate FaceTime.sqlite3 database.
File Locations
| File | Path |
|---|
| Call History DB | ~/Library/Application Support/CallHistoryDB/CallHistory.storedata |
| Call History WAL | ~/Library/Application Support/CallHistoryDB/CallHistory.storedata-wal |
| FaceTime Links DB | ~/Library/Application Support/FaceTime/FaceTime.sqlite3 |
Database Schema
ZCALLRECORD Table
CREATE TABLE ZCALLRECORD (
Z_PK INTEGER PRIMARY KEY,
Z_ENT INTEGER,
Z_OPT INTEGER,
ZANSWERED INTEGER,
ZCALL_CATEGORY INTEGER,
ZCALLTYPE INTEGER,
ZDISCONNECTED_CAUSE INTEGER,
ZHANDLE_TYPE INTEGER,
ZORIGINATED INTEGER,
ZREAD INTEGER,
ZVERIFICATIONSTATUS INTEGER,
ZDATE TIMESTAMP,
ZDURATION FLOAT,
ZADDRESS VARCHAR,
ZISO_COUNTRY_CODE VARCHAR,
ZLOCATION VARCHAR,
ZNAME VARCHAR,
ZSERVICE_PROVIDER VARCHAR,
ZUNIQUE_ID VARCHAR,
ZPARTICIPANTGROUPUUID BLOB,
ZSCREENSHARINGTYPE INTEGER,
ZCOMMUNICATIONTRUSTSCORE INTEGER,
ZJUNKCONFIDENCE INTEGER,
ZWASEMERGENCYCALL INTEGER,
ZINITIATOR INTEGER
);
ZHANDLE Table
CREATE TABLE ZHANDLE (
Z_PK INTEGER PRIMARY KEY,
Z_ENT INTEGER,
Z_OPT INTEGER,
ZTYPE INTEGER,
ZNORMALIZEDVALUE VARCHAR,
ZVALUE VARCHAR
);
Z_2REMOTEPARTICIPANTHANDLES Join Table (Group Calls)
CREATE TABLE Z_2REMOTEPARTICIPANTHANDLES (
Z_2REMOTEPARTICIPANTCALLS INTEGER,
Z_4REMOTEPARTICIPANTHANDLES INTEGER,
PRIMARY KEY (Z_2REMOTEPARTICIPANTCALLS, Z_4REMOTEPARTICIPANTHANDLES)
);
ZCONVERSATIONLINK Table (FaceTime Links)
From FaceTime.sqlite3:
CREATE TABLE ZCONVERSATIONLINK (
Z_PK INTEGER PRIMARY KEY,
Z_ENT INTEGER,
Z_OPT INTEGER,
ZACTIVATED INTEGER,
ZLIFETIMETYPE INTEGER,
ZVERSION INTEGER,
ZORIGINATORHANDLE INTEGER,
ZCREATIONDATE TIMESTAMP,
ZEXPIRATIONDATE TIMESTAMP,
ZNAME VARCHAR,
ZPSEUDONYM VARCHAR,
ZGROUPUUID BLOB,
ZPRIVATEKEY BLOB,
ZPUBLICKEY BLOB,
ZDELETIONDATE TIMESTAMP,
ZDELETEREASON INTEGER
);
Key Fields for Analysis
Call Type Values (ZCALLTYPE)
| Value | Description |
|---|
| 0 | Third-party app (CallKit) |
| 1 | Standard phone call |
| 8 | FaceTime Video |
| 16 | FaceTime Audio |
Call Category Values (ZCALL_CATEGORY)
| Value | Description |
|---|
| 1 | Phone / Telephony |
| 2 | FaceTime |
Service Provider Values (ZSERVICE_PROVIDER)
| Value | Description |
|---|
com.apple.FaceTime | FaceTime audio or video call |
com.apple.Telephony | Regular phone call (via iPhone) |
Direction (ZORIGINATED)
| Value | Direction |
|---|
| 0 | Incoming |
| 1 | Outgoing |
Handle Type (ZHANDLE_TYPE)
| Value | Type |
|---|
| 1 | Unknown |
| 2 | Phone number |
| 3 | Email address |
Disconnect Cause (ZDISCONNECTED_CAUSE)
| Value | Description |
|---|
| 0 | Ended normally |
| 6 | Missed or rejected |
| 21 | User declined / busy |
| 41 | Timeout / no answer |
FaceTime Link Deletion Reasons (ZDELETEREASON)
| Value | Reason |
|---|
| 1 | Expired |
| 5 | Manually deleted |
Forensic Queries
SELECT
datetime(cr.ZDATE + 978307200, 'unixepoch') AS call_date_utc,
CASE cr.ZCALLTYPE
WHEN 1 THEN 'Phone'
WHEN 8 THEN 'FaceTime Video'
WHEN 16 THEN 'FaceTime Audio'
ELSE 'Unknown'
END AS call_type,
CASE cr.ZORIGINATED WHEN 0 THEN 'Incoming' ELSE 'Outgoing' END AS direction,
CASE cr.ZANSWERED WHEN 1 THEN 'Yes' ELSE 'No' END AS answered,
cr.ZDURATION AS duration_seconds,
cr.ZADDRESS AS contact,
cr.ZNAME AS contact_name,
cr.ZSERVICE_PROVIDER AS service
FROM ZCALLRECORD cr
WHERE cr.ZSERVICE_PROVIDER = 'com.apple.FaceTime'
ORDER BY cr.ZDATE DESC;
SELECT
cr.ZUNIQUE_ID AS call_id,
datetime(cr.ZDATE + 978307200, 'unixepoch') AS call_date_utc,
cr.ZDURATION,
h.ZVALUE AS participant,
CASE h.ZTYPE WHEN 2 THEN 'Phone' WHEN 3 THEN 'Email' END AS handle_type
FROM ZCALLRECORD cr
JOIN Z_2REMOTEPARTICIPANTHANDLES rph ON cr.Z_PK = rph.Z_2REMOTEPARTICIPANTCALLS
JOIN ZHANDLE h ON rph.Z_4REMOTEPARTICIPANTHANDLES = h.Z_PK
WHERE cr.ZPARTICIPANTGROUPUUID IS NOT NULL
ORDER BY cr.ZDATE DESC, h.ZVALUE;
SELECT
datetime(cr.ZDATE + 978307200, 'unixepoch') AS call_date_utc,
cr.ZADDRESS,
cr.ZNAME,
CASE cr.ZCALLTYPE WHEN 8 THEN 'Video' WHEN 16 THEN 'Audio' END AS type
FROM ZCALLRECORD cr
WHERE cr.ZANSWERED = 0
AND cr.ZORIGINATED = 0
AND cr.ZSERVICE_PROVIDER = 'com.apple.FaceTime'
ORDER BY cr.ZDATE DESC;
SELECT
datetime(cl.ZCREATIONDATE + 978307200, 'unixepoch') AS created_utc,
datetime(cl.ZEXPIRATIONDATE + 978307200, 'unixepoch') AS expires_utc,
cl.ZNAME AS link_name,
cl.ZPSEUDONYM AS url_slug,
cl.ZACTIVATED AS activated,
h.ZVALUE AS creator,
CASE cl.ZDELETEREASON WHEN 1 THEN 'Expired' WHEN 5 THEN 'Manual' END AS delete_reason
FROM ZCONVERSATIONLINK cl
LEFT JOIN ZHANDLE h ON cl.ZORIGINATORHANDLE = h.Z_PK
ORDER BY cl.ZCREATIONDATE DESC;
Timestamps
All timestamps use Core Data epoch (seconds since 2001-01-01 00:00:00 UTC):
Unix timestamp = Core Data timestamp + 978307200
| Column | Table | Description |
|---|
ZDATE | ZCALLRECORD | When the call occurred |
ZCREATIONDATE | ZCONVERSATIONLINK | When the FaceTime Link was created |
ZEXPIRATIONDATE | ZCONVERSATIONLINK | When the FaceTime Link expires |
ZDELETIONDATE | ZCONVERSATIONLINK | When the FaceTime Link was deleted |
Duration (ZDURATION) is stored as a float in seconds, not as a timestamp.
Analysis Notes
- FaceTime vs Phone: Use
ZSERVICE_PROVIDER for definitive service identification. ZCALLTYPE and ZCALL_CATEGORY provide additional context but ZSERVICE_PROVIDER is the most reliable discriminator. - Group call detection: A non-null
ZPARTICIPANTGROUPUUID indicates a group call. The individual participants are found in the Z_2REMOTEPARTICIPANTHANDLES join table. - Zero-duration calls: A call with
ZDURATION = 0 and ZANSWERED = 0 typically indicates a missed call or a call that was declined before being answered. - Screen sharing:
ZSCREENSHARINGTYPE > 0 indicates that screen sharing (SharePlay) was active during the call. This is only available on macOS 13 Ventura and later. - Emergency calls:
ZWASEMERGENCYCALL = 1 identifies emergency service calls. These are always of high forensic significance. - STIR/SHAKEN verification: The
ZVERIFICATIONSTATUS column reflects caller ID verification status, which can help identify spoofed call attempts. - Spam confidence:
ZJUNKCONFIDENCE reflects Apple's assessment of whether the call is spam. Higher values indicate greater spam likelihood. - FaceTime Link privacy: macfor intentionally excludes
ZPRIVATEKEY and ZPUBLICKEY from collection. The ZPSEUDONYM column provides the unique URL component without exposing cryptographic material. - Contact resolution: The
ZNAME column may contain a pre-resolved contact name. Cross-reference ZADDRESS with the Contacts AddressBook database for more complete identity information.
Version Differences
| macOS Version | Schema Changes |
|---|
| 10.13 High Sierra | CallHistory.storedata introduced with ZCALLRECORD |
| 10.15 Catalina | Added ZJUNKCONFIDENCE, ZVERIFICATIONSTATUS |
| 12 Monterey | FaceTime.sqlite3 with ZCONVERSATIONLINK introduced |
| 13 Ventura | ZSCREENSHARINGTYPE column added |
| 14 Sonoma | Schema version 42; minor additions |
| Tool | Capability |
|---|
| macfor | Full call history and FaceTime Links collection with participant resolution |
| iLEAPP | Parses CallHistory.storedata |
| APOLLO | Call history analysis module |
| sqlite3 CLI | Manual querying with Core Data timestamp conversion |
References