Chrome

Chrome History

Overview

Chrome stores browsing history, downloads, and search terms in a single SQLite database named History within each profile directory. This database records every URL visited, the time and manner of each visit, files downloaded from the internet, and search queries performed via the omnibox.

The History database is one of the most forensically valuable Chrome artifacts, providing a detailed timeline of user web activity with visit-level granularity. Unlike some browsers that only record the most recent visit to each URL, Chrome maintains a separate record for every individual visit, enabling precise reconstruction of browsing patterns.

File Locations

ArtifactPath
History database~/Library/Application Support/Google/Chrome/{Profile}/History
Journal file~/Library/Application Support/Google/Chrome/{Profile}/History-journal
WAL file~/Library/Application Support/Google/Chrome/{Profile}/History-wal
SHM file~/Library/Application Support/Google/Chrome/{Profile}/History-shm

Replace {Profile} with the profile directory name (e.g., Default, Profile 1). The same structure applies to Chrome Canary and Chromium at their respective base paths.

Database Schema

urls Table

The urls table contains one row per unique URL visited. It stores aggregate statistics for each URL across all visits.

CREATE TABLE urls (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    url LONGVARCHAR,
    title LONGVARCHAR,
    visit_count INTEGER DEFAULT 0 NOT NULL,
    typed_count INTEGER DEFAULT 0 NOT NULL,
    last_visit_time INTEGER NOT NULL,      -- WebKit timestamp
    hidden INTEGER DEFAULT 0 NOT NULL
);

visits Table

The visits table records each individual visit to a URL. This is the primary table for timeline reconstruction.

CREATE TABLE visits (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    url INTEGER NOT NULL,                   -- Foreign key to urls.id
    visit_time INTEGER NOT NULL,            -- WebKit timestamp
    from_visit INTEGER,                     -- Referring visit ID
    transition INTEGER DEFAULT 0 NOT NULL,  -- Transition type bitmask
    segment_id INTEGER,
    visit_duration INTEGER DEFAULT 0 NOT NULL,  -- Duration in microseconds
    incremented_omnibox_typed_score BOOLEAN DEFAULT FALSE NOT NULL,
    opener_visit INTEGER,
    originator_cache_guid TEXT,
    originator_visit_id INTEGER,
    originator_from_visit INTEGER,
    originator_opener_visit INTEGER,
    is_known_to_sync BOOLEAN DEFAULT FALSE NOT NULL,
    consider_for_ntp_most_visited BOOLEAN DEFAULT FALSE NOT NULL,
    publicly_routable BOOLEAN DEFAULT FALSE NOT NULL
);

downloads Table

The downloads table records all file download events.

CREATE TABLE downloads (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    guid VARCHAR NOT NULL,
    current_path LONGVARCHAR NOT NULL,
    target_path LONGVARCHAR NOT NULL,
    start_time INTEGER NOT NULL,            -- WebKit timestamp
    received_bytes INTEGER NOT NULL,
    total_bytes INTEGER NOT NULL,
    state INTEGER NOT NULL,                 -- 0=in_progress, 1=complete, 2=cancelled, 3=interrupted
    danger_type INTEGER NOT NULL,
    interrupt_reason INTEGER NOT NULL,
    hash BLOB NOT NULL,
    end_time INTEGER NOT NULL,              -- WebKit timestamp
    opened INTEGER NOT NULL,
    last_access_time INTEGER NOT NULL,
    transient INTEGER NOT NULL,
    referrer VARCHAR NOT NULL,
    site_url VARCHAR NOT NULL,
    tab_url VARCHAR NOT NULL,
    tab_referrer_url VARCHAR NOT NULL,
    http_method VARCHAR NOT NULL,
    by_ext_id VARCHAR NOT NULL,
    by_ext_name VARCHAR NOT NULL,
    etag VARCHAR NOT NULL,
    last_modified VARCHAR NOT NULL,
    mime_type VARCHAR(255) NOT NULL,
    original_mime_type VARCHAR(255) NOT NULL
);

downloads_url_chains Table

Records redirect chains for downloads, linking the original URL through any intermediate redirects to the final download URL.

CREATE TABLE downloads_url_chains (
    id INTEGER NOT NULL,           -- Foreign key to downloads.id
    chain_index INTEGER NOT NULL,
    url LONGVARCHAR NOT NULL,
    PRIMARY KEY (id, chain_index)
);

keyword_search_terms Table

Records search queries performed through the omnibox, linked to the URL that was visited as a result.

CREATE TABLE keyword_search_terms (
    keyword_id INTEGER NOT NULL,
    url_id INTEGER NOT NULL,       -- Foreign key to urls.id
    term LONGVARCHAR NOT NULL,
    normalized_term LONGVARCHAR NOT NULL
);

content_annotations Table (Chrome 91+)

Stores content-level metadata for visits, including page categories and search terms.

CREATE TABLE content_annotations (
    visit_id INTEGER PRIMARY KEY,
    visibility_score NUMERIC,
    categories VARCHAR,
    page_topics_model_version INTEGER,
    annotation_flags INTEGER NOT NULL DEFAULT 0,
    entities VARCHAR,
    related_searches VARCHAR,
    search_normalized_url VARCHAR,
    search_terms LONGVARCHAR,
    alternative_title VARCHAR,
    page_language VARCHAR,
    password_state INTEGER DEFAULT 0 NOT NULL,
    has_url_keyed_image BOOLEAN DEFAULT FALSE NOT NULL
);

context_annotations Table (Chrome 92+)

Stores context-level metadata for visits, including duration and browser context.

CREATE TABLE context_annotations (
    visit_id INTEGER PRIMARY KEY,
    context_annotation_flags INTEGER NOT NULL,
    duration_since_last_visit INTEGER,
    page_end_reason INTEGER,
    total_foreground_duration INTEGER,
    browser_type INTEGER DEFAULT 0 NOT NULL,
    window_id INTEGER DEFAULT -1 NOT NULL,
    tab_id INTEGER DEFAULT -1 NOT NULL,
    task_id INTEGER DEFAULT -1 NOT NULL,
    root_task_id INTEGER DEFAULT -1 NOT NULL,
    parent_task_id INTEGER DEFAULT -1 NOT NULL,
    response_code INTEGER DEFAULT 0 NOT NULL
);

Key Fields for Analysis

Visit Analysis

  • visits.visit_time: The exact timestamp of each visit (WebKit format). This is the primary field for timeline reconstruction.
  • visits.transition: A bitmask indicating how the user arrived at the page. The lower 8 bits encode the core transition type; upper bits encode qualifiers.
  • visits.visit_duration: Time spent on the page in microseconds. Zero means not recorded (common in older versions).
  • visits.from_visit: Links to the referring visit, enabling reconstruction of browsing chains.
  • urls.typed_count: How many times the user explicitly typed this URL, distinguishing intentional navigation from link-following.
  • urls.hidden: Whether the URL is hidden from Chrome's history UI. Hidden entries are still present in the database.

Download Analysis

  • downloads.state: 0 = in progress, 1 = complete, 2 = cancelled, 3 = interrupted.
  • downloads.danger_type: Indicates whether Chrome flagged the download as dangerous. Values range from 0 (not dangerous) through 19 (blocked unsupported file type).
  • downloads.by_ext_id / downloads.by_ext_name: Identifies downloads initiated by browser extensions.
  • downloads.tab_url: The page the user was viewing when they initiated the download.
  • downloads.opened: Whether the user opened the file after downloading.

Search Term Analysis

  • keyword_search_terms.term: The raw search query entered by the user.
  • keyword_search_terms.normalized_term: A cleaned/normalised version for deduplication.

Timestamps

All timestamps in the History database use WebKit/Chrome format: microseconds since 1601-01-01 00:00:00 UTC.

unix_microseconds = webkit_timestamp - 11644473600000000
FieldFormatNotes
urls.last_visit_timeWebKitMost recent visit to this URL
visits.visit_timeWebKitTime of this specific visit
visits.visit_durationMicroseconds (raw)Duration on page, not a timestamp
downloads.start_timeWebKitWhen download began
downloads.end_timeWebKitWhen download completed (0 if incomplete)
downloads.last_access_timeWebKitWhen the downloaded file was last accessed

Transition Types

Chrome encodes the method of navigation as a bitmask in the visits.transition column. Extract the core type from the lower 8 bits: core_type = transition & 0xFF.

Core TypeValueDescription
LINK0User clicked a link on another page
TYPED1User typed the URL in the omnibox
AUTO_BOOKMARK2Auto-navigation from a bookmark
AUTO_SUBFRAME3Automatic subframe navigation (ads, embeds)
MANUAL_SUBFRAME4User-initiated subframe navigation
GENERATED5Navigation generated by script
AUTO_TOPLEVEL6Automatic top-level navigation
FORM_SUBMIT7Form submission
RELOAD8Page reload
KEYWORD9Keyword search from omnibox
KEYWORD_GENERATED10Keyword with URL substitution

Qualifier flags (OR'd with the core type in upper bits):

QualifierBitmaskDescription
BLOCKED0x00800000Navigation was blocked by an extension
FORWARD_BACK0x01000000Forward or back button navigation
FROM_ADDRESS_BAR0x02000000Initiated from the address bar
HOME_PAGE0x04000000Home page navigation
FROM_API0x08000000Initiated by an extension API call
CHAIN_START0x10000000Start of a redirect chain
CHAIN_END0x20000000End of a redirect chain
CLIENT_REDIRECT0x40000000Client-side redirect (JavaScript, meta refresh)
SERVER_REDIRECT0x80000000Server-side redirect (HTTP 301/302)

Danger Types

The downloads.danger_type field indicates Chrome's safety assessment of each download:

TypeValueDescription
NOT_DANGEROUS0No danger detected
DANGEROUS_FILE1File extension considered dangerous
DANGEROUS_URL2URL flagged by Safe Browsing
DANGEROUS_CONTENT3Content flagged as dangerous
MAYBE_DANGEROUS_CONTENT4Potentially dangerous content
UNCOMMON_CONTENT5Uncommon file type
USER_VALIDATED6User explicitly overrode warning
DANGEROUS_HOST7Host has poor reputation
POTENTIALLY_UNWANTED8Potentially unwanted program
ALLOWLISTED_BY_POLICY9Enterprise policy allowlist
BLOCKED_PASSWORD_PROTECTED11Blocked: password-protected archive
BLOCKED_TOO_LARGE12Blocked: file too large for scanning
DEEP_SCANNED_SAFE16Passed deep content scan
DEEP_SCANNED_OPENED_DANGEROUS17User opened despite scan warning

Analysis Notes

  • The from_visit field in the visits table allows reconstruction of referral chains. Following this chain reveals how a user navigated from one site to another.
  • A typed_count > 0 on a URL indicates deliberate user action rather than passive link-following or redirects.
  • The hidden flag is set for URLs that Chrome hides from its own UI (such as certain redirect intermediaries), but these URLs are still forensically relevant.
  • Downloads with danger_type = 6 (USER_VALIDATED) indicate the user explicitly chose to keep a file that Chrome warned about.
  • The by_ext_id field on downloads can identify if an extension initiated the download, which may be relevant in malware investigations.
  • Search terms from keyword_search_terms provide direct insight into what the user was looking for, without needing to parse search engine URLs.

Version Differences

VersionChange
Chrome 80+Baseline schema supported by macfor
Chrome 91Added content_annotations table with page categories and search metadata
Chrome 92Added context_annotations table with foreground duration and browser context
Chrome 93Added clusters table for visit grouping
Chrome 100+Added originator_* columns to visits for sync attribution
Chrome 118+Added publicly_routable column to visits

macfor uses dynamic column detection to handle these differences gracefully, querying only the columns present in the database.

Tool Support

ToolCapability
macforCollects raw database, parses visits with transition types, downloads with danger classification, and search terms
HindsightComprehensive Chrome history analysis with timeline output
DB Browser for SQLiteManual inspection of all tables
sqlite3 CLICommand-line queries against the History database

References

Previous
Chrome Overview