# Technical Documentation: chromiumembedded/cef

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/chromiumembedded/cef)

### Overview (`README.md`)

The Chromium Embedded Framework (CEF) is a simple framework for embedding Chromium-based browsers in other applications.

# Quick Links

* Project Page - https://github.com/chromiumembedded/cef
* Documentation - https://chromiumembedded.github.io/cef/
* Tutorial - https://chromiumembedded.github.io/cef/tutorial
* General Usage - https://chromiumembedded.github.io/cef/general_usage
* Master Build Quick-Start - https://chromiumembedded.github.io/cef/master_build_quick_start
* Branches and Building - https://chromiumembedded.github.io/cef/branches_and_building
* Announcements - https://groups.google.com/forum/#!forum/cef-announce
* Support Forum - http://www.magpcss.org/ceforum/
* Issue Tracker - https://github.com/chromiumembedded/cef/issues
* C++ API Docs - [Stable release docs](https://cef-builds.spotifycdn.com/docs/stable.html) / [Beta release docs](https://cef-builds.spotifycdn.com/docs/beta.html)
* Downloads - https://cef-builds.spotifycdn.com/index.html
* Donations - https://github.com/sponsors/magreenblatt

# Introduction

CEF is a BSD-licensed open source project founded by Marshall Greenblatt in 2008 and based on the [Google Chromium](http://www.chromium.org/Home) project. Unlike the Chromium project itself, which focuses mainly on Google Chrome application development, CEF focuses on facilitating embedded browser use cases in third-party applications. CEF insulates the user from the underlying Chromium and Blink code complexity by offering production-quality stable APIs, release branches tracking specific Chromium releases, and binary distributions. Most features in CEF have default implementations that provide rich functionality while requiring little or no integration work from the user. There are currently over 100 million installed instances of CEF around the world embedded in products from a wide range of companies and industries. A partial list of companies and products using CEF is available on the [CEF Wikipedia page](http://en.wikipedia.org/wiki/Chromium_Embedded_Framework#Applications_using_CEF). Some use cases for CEF include:

* Embedding an HTML5-compliant Web browser control in an existing native application.
* Creating a light-weight native “shell” application that hosts a user interface developed primarily using Web technologies.
* Rendering Web content “off-screen” in applications that have their own custom drawing frameworks.
* Acting as a host for automated testing of existing Web properties and applications.

CEF supports a wide range of programming languages and operating systems and can be easily integrated into both new and existing applications. It was designed from the ground up with both performance and ease of use in mind. The base framework includes C and C++ programming interfaces exposed via native libraries that insulate the host application from Chromium and Blink implementation details. It provides close integration between the browser and the host application including support for custom plugins, protocols, JavaScript objects and JavaScript extensions. The host application can optionally control resource loading, navigation, context menus, printing and more, while taking advantage of the same performance and HTML5 technologies available in the Google Chrome Web browser.

Numerous individuals and organizations contribute time and resources to support CEF development, but more involvement from the community is always welcome. This includes support for both the core CEF project and external projects that integrate CEF with additional programming languages and frameworks (see the "External Projects" section below). If you are interested in donating time to help with CEF development please see the "Helping Out" section below. If you are interested in donating money to support general CEF development and infrastructure efforts please visit the [CEF Sponsors](https://github.com/sponsors/magreenblatt) page.

# Getting Started

Users new to CEF development should start by reading the [Tutorial](https://chromiumembedded.github.io/cef/tutorial) for an overview of CEF usage and then proceed to the [General Usage](https://chromiumembedded.github.io/cef/general_usage) page for a more in-depth discussion of architectural and usage issues. Complete API documentation is available [here](https://cef-builds.spotifycdn.com/docs/stable.html). CEF support and related discussion is available on the [CEF Forum](http://www.magpcss.org/ceforum/).

# Binary Distributions

Binary distributions, which include all files necessary to build a CEF-based application, are available on the [Downloads](https://cef-builds.spotifycdn.com/index.html) page. Binary distributions are stand-alone and do not require the download of CEF or Chromium source code. Symbol files for debugging binary distributions of libcef can also be downloaded from the above links.

# Source Distributions

The CEF project is an extension of the Chromium project. CEF maintains development and release branches that track Chromium branches. CEF source code can be downloaded, built and packaged manually or with automated tools. Visit the [Branches and Building](https://chromiumembedded.github.io/cef/branches_and_building) page for more information.

# Security Updates

CEF is based on Chromium, so Chromium security vulnerabilities (CVEs) are likely to affect CEF using the same Chromium version. Applications that distribute CEF should keep their CEF version up to date.

Security fixes are announced in Stable Channel updates on the [Chrome Releases blog](https://chromereleases.googleblog.com/). To receive updates automatically, subscribe to the blog's [feed](https://chromereleases.googleblog.com/feeds/posts/default) using a feed reader or a service that delivers feed updates by email. CEF does not provide a separate security announcement mailing list. See the [Chromium security documentation](https://www.chromium.org/Home/chromium-security/#how-can-i-get-access-to-chromium-vulnerabilities) for additional information, including eligibility for advance notification.

There may be a delay between Chromium release announcements and the availability of corresponding CEF builds. See [Branches and Building](https://chromiumembedded.github.io/cef/branches_and_building#current-release-branches-supported) for supported branches and [Downloads](https://cef-builds.spotifycdn.com/index.html) for available builds.

# External Projects

The base CEF framework includes support for the C and C++ programming languages. Thanks to the hard work of external maintainers CEF can integrate with a number of other programming languages and frameworks. These external projects are not maintained by CEF so please contact the respective project maintainer if you have any questions or issues.

* .Net (CEF3) - https://github.com/cefsharp/CefSharp
* .Net (CEF1) - https://bitbucket.org/fddima/cefglue
* .Net/Mono (CEF3) - https://gitlab.com/xiliumhq/chromiumembedded/cefglue
* Delphi - https://github.com/hgourvest/dcef3
* Delphi - https://github.com/salvadordf/CEF4Delphi
* Go - https://github.com/CzarekTomczak/cef2go
* Go - https://github.com/energye/energy
* Java - https://github.com/chromiumembedded/java-cef
* Python - http://code.google.com/p/cefpython/

If you're the maintainer of a project not listed above and would like your project listed here please either post to the [CEF Forum](http://www.magpcss.org/ceforum/) or contact Marshall directly.

# Helping Out

CEF is still very much a work in progress. Some ways that you can help out:

\- Vote for issues in the [CEF issue tracker](https://github.com/chromiumembedded/cef/issues) that are important to you.

\- Report bugs or request features via the [issue tracker](https://github.com/chromiumembedded/cef/issues). Use the [CEF Forum](http://magpcss.org/ceforum) for usage questions.

\- Write unit tests for new or existing functionality.

\- Submit pull requests. View open issues or search for TODO(cef) in the source code for ideas.

See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines on submitting changes, code style, commit messages, and AI tool usage.

---

### Overview (`docs/README.md`)

The Chromium Embedded Framework (CEF) is a simple framework for embedding Chromium-based browsers in other applications. Visit the [Project Overview page](https://github.com/chromiumembedded/cef) for more information.


***

# Wiki Pages

* [Tutorial](tutorial.md) - Tutorial explaining how to create a simple application using CEF3.
* [Hands On Tutorial](hands_on_tutorial.md) - Step-by-step hands-on tutorial that teaches CEF by progressively modifying the cefsimple example.
* [Master Build Quick Start](master_build_quick_start.md) - Quick-start guide for building the CEF/Chromium master (development) branch.
* [Branches And Building](branches_and_building.md) - Information about CEF branches and instructions for downloading, building and packaging source code.
* [Contributing With Git](contributing_with_git.md) - How to contribute code changes to CEF using Git.
* [General Usage](general_usage.md) - Overview and general usage of CEF3.
* [Java Script Integration](javascript_integration.md) - How to use V8 JavaScript integration in client applications.
* [Architecture](architecture.md) - Overview of the CEF architecture.
* [Api Versioning](api_versioning.md) - Overview and usage of CEF API versioning.
* [Using Chrome Driver](using_chrome_driver.md) - How to use ChromeDriver and Selenium to automate CEF-based applications.
* [Using Address Sanitizer](using_address_sanitizer.md) - How to use AddressSanitizer with CEF-based applications.
* [Using The CAPI](using_the_capi.md) - How to use the C API in your client application.
* [Linking Different Run Time Libraries](linking_different_runtime_libraries.md) - How to link CEF against a different run-time library.
* [Chromium Update](chromium_update.md) - How to update CEF to use the newest Chromium revision.
* [Automated Build Setup](automated_build_setup.md) - How to set up an automated build system for CEF.
* [Crash Reporting](crash_reporting.md) - How to handle crash reporting from CEF-based applications.
* [Code Signing](code_signing.md) - How to sign CEF-based applications on Windows and macOS, including macOS notarization.
* [Sandbox Setup](sandbox_setup.md) - Sandbox usage and requirements for CEF.
* [Installer](installer.md) - Support for CEF shared installs on Windows.

The complete list of CEF Wiki pages is available [here](.).

# External Links

* Support Forum - <http://www.magpcss.org/ceforum/>
* C++ API Docs - [Stable release docs](https://cef-builds.spotifycdn.com/docs/stable.html) / [Beta release docs](https://cef-builds.spotifycdn.com/docs/beta.html)
* Downloads - <https://cef-builds.spotifycdn.com/index.html>
* Donations - <http://www.magpcss.org/ceforum/donate.php>

---

### Overview (`tests/README.md`)

# CEF Test Applications

This directory contains sample applications and test suites demonstrating the Chromium Embedded Framework (CEF).

## Sample Applications

### [cefsimple](cefsimple/)

Minimal C++ browser application - the recommended starting point for learning CEF.

- **Purpose:** Learning CEF basics
- **Complexity:** ~10 source files
- **Best for:** Understanding CEF architecture and fundamental APIs
- **Tutorial:** [CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial) provides detailed walkthrough

### [cefsimple_capi](cefsimple_capi/)

Pure C implementation of cefsimple using the CEF C API.

- **Purpose:** C API reference implementation
- **Language:** Pure C (C11), no C++
- **Best for:** Embedding CEF in C projects or when C++ is unavailable
- **Documentation:** [Using the CAPI](https://chromiumembedded.github.io/cef/using_the_capi)

### [cefclient](cefclient/)

Comprehensive sample application demonstrating advanced CEF features.

- **Purpose:** Feature demonstration and manual testing
- **Complexity:** ~100+ source files
- **Features:** Full CEF API coverage, built-in test framework, multiple UI modes
- **Best for:** Reference implementation, exploring advanced features

## Test Suite

### [ceftests](ceftests/)

Automated unit test suite for CEF API validation.

- **Purpose:** Automated regression testing
- **Framework:** Google Test (gtest)
- **Coverage:** Comprehensive CEF API testing across all platforms
- **Best for:** CI/CD integration, validating CEF releases

## Shared Code

### [shared](shared/)

Common utilities and helpers used by cefclient and ceftests.

- Delegate pattern framework for application customization
- Message loop implementations (standard, external pump, multi-threaded)
- Cross-platform resource loading and file utilities
- **Not used by** cefsimple or cefsimple_capi (self-contained examples)

## Learning Path

**New to CEF?** Follow this recommended path:

1. **Start with [cefsimple](cefsimple/)** and the [CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial) to understand CEF architecture
2. **Explore [cefclient](cefclient/)** to see advanced features and integration patterns
3. **Review [ceftests](ceftests/)** to understand API usage and testing patterns
4. **Study [shared](shared/)** code for reusable patterns and best practices

For C API development, substitute [cefsimple_capi](cefsimple_capi/) for cefsimple and consult [Using the CAPI](https://chromiumembedded.github.io/cef/using_the_capi).

## References

- [CEF Project](https://github.com/chromiumembedded/cef) - Main repository
- [CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial) - Detailed architecture walkthrough
- [CEF General Usage](https://chromiumembedded.github.io/cef/general_usage) - Complete API documentation
- [CEF Forum](https://magpcss.org/ceforum/) - Community support and discussions

---

### Overview (`tests/cefclient/README.md`)

# CEF Client Sample Application

This directory contains the comprehensive CEF sample application demonstrating advanced browser integration features and CEF capabilities.

## Overview

**cefclient** is the primary CEF sample application showcasing:

- **Complete feature set** - Demonstrates most CEF APIs and integration patterns
- **Test framework** - Built-in tests for various CEF functionality
- **Advanced features** - OSR (off-screen rendering), process messaging, scheme handlers, and more
- **Multi-window support** - Window management, popups, and DevTools
- **Cross-platform** - Full implementations for Windows, Linux, and macOS

### Comparison with cefsimple

| Feature | cefclient | cefsimple |
|---------|-----------|-----------|
| **Purpose** | Comprehensive feature demo & testing | Minimal learning example |
| **Complexity** | ~100+ source files | ~10 source files |
| **Features** | Full CEF API coverage | Basic browser only |
| **Best for** | Reference implementation, testing | Learning CEF basics |

**For learning CEF:** Start with [cefsimple](../cefsimple/) to understand the basics, then explore cefclient for advanced features.

## Learning Resources

**Understanding cefclient architecture:**

1. **[CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial)** - Covers cefsimple architecture, which provides the foundation
2. **[CEF General Usage](https://chromiumembedded.github.io/cef/general_usage)** - Complete CEF API documentation
3. **This application** - Explore the built-in tests and advanced implementations

## Architecture

### Core Components

- **MainContext** (`browser/main_context*`) - Application state and CEF initialization
- **RootWindowManager** (`browser/root_window_manager*`) - Window creation and management
- **ClientHandler** (`browser/client_handler*`) - CEF client implementation with event handlers
- **RootWindow** (`browser/root_window*`) - Individual browser window management
- **TestRunner** (`browser/test_runner*`) - Test coordination and execution

### Directory Structure

- **browser/** - Browser process implementation (main application logic)
- **renderer/** - Renderer process code (runs in isolated renderer processes)
- **common/** - Shared code used by multiple processes
- **resources/** - HTML/JS/CSS test pages and resources
- **mac/**, **win/** - Platform-specific resources and helpers

### Platform Entry Points

- **cefclient_gtk.cc** - Linux (GTK) entry point
- **cefclient_mac.mm** - macOS (Cocoa) entry point
- **cefclient_win.cc** - Windows (Win32) entry point

## Key Features Demonstrated

### Basic Browser Features

- Window creation and management
- Navigation and lifecycle
- JavaScript execution
- Resource loading and scheme handlers

### Advanced Features

- **Off-Screen Rendering (OSR)** - Windowless rendering with custom painting
- **Process messaging** - Communication between browser and renderer processes
- **DevTools integration** - Chrome Developer Tools
- **Downloads** - Download handling and management
- **Dialogs** - File dialogs, JavaScript dialogs, context menus
- **Performance** - DOM access, frame rate control
- **Extensions** - Chrome extension loading (Chrome style)

### Testing

The application includes numerous tests accessible via the **Tests** menu:

- Binding tests (JavaScript ↔ C++ communication)
- Window management tests
- Request/response tests
- JavaScript execution tests
- Scheme handler tests
- And many more...

## UI Frameworks

cefclient supports multiple UI approaches:

- **Native** - Platform-specific UI (GTK, Cocoa, Win32)
- **Views** - Cross-platform CEF Views framework
- **OSR** - Custom rendering without native windows

## Browser Styles

cefclient uses the Chrome bootstrap and supports two browser styles:

- **Chrome style** (default) - Modern Chrome browser with advanced features (autofill, extensions, gamepad, etc.) and standard Chrome UI (toolbars, dialogs, etc.)
- **Alloy style** - Traditional CEF browser based on the Chromium Content API, provides more flexibility for custom UI

Use command-line flags to select the browser style and other options.

## Exploring Features

Try these different modes to explore various cefclient features:

```bash
# Chrome style (default):
cefclient

# Alloy style:
cefclient --use-alloy-style
cefclient --use-alloy-style --use-native
cefclient --off-screen-rendering-enabled

# Multi-threaded message loop (Windows/Linux only):
cefclient --multi-threaded-message-loop
cefclient --use-alloy-style --multi-threaded-message-loop

# Chrome style + native parent (Windows/Linux only):
cefclient --use-native
```

**What each mode demonstrates:**

- **Default** - Chrome style with Views framework
- **--use-alloy-style** - Traditional CEF browser
- **--use-native** - Platform-specific native UI instead of Views
- **--off-screen-rendering-enabled** - OSR mode (windowless rendering)
- **--multi-threaded-message-loop** - Alternative threading model

**Note:** On macOS, use `open cefclient.app --args <flags>` to pass command-line arguments.

Once running, explore the **Tests** menu to see demonstrations of various CEF features.

## C API Version

Unlike cefsimple, cefclient does **not** have a C API equivalent due to its complexity. For a C API example, see [cefsimple_capi](../cefsimple_capi/).

## References

- [CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial) - Start with cefsimple concepts
- [CEF General Usage](https://chromiumembedded.github.io/cef/general_usage) - Complete API documentation
- [cefsimple](../cefsimple/) - Minimal example for learning basics
- [CEF Forum](https://magpcss.org/ceforum/) - Community support and discussions

---

### Overview (`tests/cefsimple/README.md`)

# CEF Simple C++ Example

This directory contains a minimal CEF browser application written in C++ using the CEF C++ API.

## Overview

**cefsimple** is the canonical minimal CEF application demonstrating:

- **C++ implementation** - Uses CEF C++ API with automatic reference counting
- **Basic browser functionality** - Window creation, navigation, and lifecycle management
- **Cross-platform** - Supports Windows, Linux, and macOS
- **Minimal code** - Simple architecture suitable for learning CEF basics

### C API Version

A pure C implementation of this example is available at [../cefsimple_capi/](../cefsimple_capi/). The C version demonstrates the same functionality using the CEF C API with manual reference counting.

**When to use each:**

- **Use cefsimple (C++)** - For production applications and most use cases
- **Use cefsimple_capi (C)** - When C++ is not available or for embedding in C projects

## Learning Resources

**New to CEF?** Start with the [CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial), which provides a detailed walkthrough of this exact example:

- **Architecture overview** - CEF processes, threads, and callbacks
- **Code walkthrough** - Detailed explanation of each file and function
- **Program flow** - How cefsimple initializes and runs
- **Key concepts** - CefApp, CefClient, handlers, and browser lifecycle

The Tutorial is the recommended starting point for understanding how CEF applications work.

For complete API documentation, see [General Usage](https://chromiumembedded.github.io/cef/general_usage).

## Architecture

### Core Files

- **simple_app.h/cc** - Application handler (CefApp)
- **simple_handler.h/cc** - Client handler with display, life span, and load handlers

### Platform-Specific Files

#### Windows

- **cefsimple_win.cc** - Windows entry point (wWinMain)
- **simple_handler_win.cc** - Windows-specific handler implementation

#### Linux

- **cefsimple_linux.cc** - Linux entry point (main)
- **simple_handler_linux.cc** - Linux/X11-specific handler implementation

#### macOS

- **cefsimple_mac.mm** - macOS entry point with NSApplication integration
- **simple_handler_mac.mm** - macOS-specific handler implementation
- **process_helper_mac.cc** - Helper process entry point

## Key Features

- **Automatic reference counting** - CefRefPtr handles object lifetime
- **Helper window** - Creates a browser window with navigation controls
- **Error handling** - Displays error pages for failed navigations
- **Cross-platform UI** - Uses Views framework for consistent UI

## Maintenance Pattern

This is the primary CEF sample application. Changes to CEF features, API updates, or bug fixes should be applied here first, then ported to cefsimple_capi (the C version).

**Typical workflow:**

1. Update cefsimple (C++ version) with new features or API changes
2. Port equivalent changes to cefsimple_capi using C API patterns
3. Result: Both examples demonstrate the same functionality

## References

- [CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial) - Detailed walkthrough of this example
- [CEF General Usage](https://chromiumembedded.github.io/cef/general_usage) - Complete API documentation
- [CEF C++ API Documentation](https://chromiumembedded.github.io/cef/)
- [C API Version](../cefsimple_capi/) - Pure C implementation of this example

---

### Overview (`tests/cefsimple_capi/README.md`)

# CEF Simple C API Example

This directory contains a pure C implementation of the cefsimple sample application using the CEF C API (CAPI).

## Overview

This is a conversion of `cef/tests/cefsimple` from C++ to pure C, demonstrating:

- **Pure C implementation** - No C++ code, uses C11 standard
- **Manual reference counting** - Using atomic operations for thread safety
- **CEF C API usage** - All CEF calls use the C API (`include/capi/*.h`)
- **Cross-platform** - Supports Windows, Linux, and macOS

### Maintenance Pattern

This project serves as a reference C API implementation that mirrors the C++ `cefsimple` example. When changes are made to `cef/tests/cefsimple` (the C++ version), **equivalent changes should be applied to this project** using the C API patterns.

**Intended workflow:**

1. Changes are made to C++ `cefsimple` (new features, API updates, bug fixes)
2. Claude Code analyzes the C++ changes
3. Claude Code applies equivalent changes to `cefsimple_capi` using CEF C API
4. Result: Both examples stay in sync, demonstrating the same functionality in C++ and C

**Example Claude prompt:**
```
Apply the equivalent changes from the latest commits in cef/tests/cefsimple
to cef/tests/cefsimple_capi, converting the C++ code to C API patterns.
Use the reference counting and handler patterns from UsingTheCAPI.md.
```

This ensures the C API example remains current and demonstrates the same CEF features as the C++ version.

## Learning Path

For best results, we recommend this learning path:

1. **[CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial)** - Start here to understand CEF architecture and concepts using the C++ cefsimple example
2. **[Using the CAPI](https://chromiumembedded.github.io/cef/using_the_capi)** - Learn C-specific patterns and reference counting rules
3. **This example (cefsimple_capi)** - See the C API implementation in practice

**Note:** The Tutorial uses C++ code examples, but the architectural concepts (processes, threads, callbacks, program flow) apply equally to the C API version.

## Architecture

### Utility Modules

- **ref_counted.h** - Macros for implementing reference counting (`IMPLEMENT_REFCOUNTING_SIMPLE`, `IMPLEMENT_REFCOUNTING_MANUAL`, `INIT_CEF_BASE_REFCOUNTED`)
- **simple_utils.h** - Common utilities (`CHECK` macro for invariant validation)
- **simple_browser_list.h/c** - Dynamic list of browser instances with automatic reference counting

### Application Core

- **simple_app.h/c** - Application handler (`cef_app_t`) and browser process handler

### Client Handler Module

- **simple_handler.h** - Client handler interface and structure definitions
- **simple_handler.c** - Main client handler implementation, public API, and browser close operations
- **simple_display_handler.c** - Display handler (title change notifications)
- **simple_life_span_handler.c** - Life span handler (browser lifecycle management)
- **simple_load_handler.c** - Load handler (error page display)

### Views Framework

- **simple_views.h/c** - Browser view and window delegates for Views-based UI

### Platform-Specific Files

#### Windows

- **cefsimple_win.c** - Windows entry point (wWinMain)
- **simple_handler_win.c** - Windows-specific handler (window title updates)

#### Linux

- **cefsimple_linux.c** - Linux entry point (main)
- **simple_handler_linux.c** - Linux/X11-specific handler (window title updates)

#### macOS

- **cefsimple_mac.m** - macOS entry point with NSApplication integration
- **simple_handler_mac.m** - macOS-specific handler (window title updates)
- **process_helper_mac.c** - Helper process entry point

## Key Differences from C++ Version

The C API requires significantly different patterns than C++:

- **Manual reference counting** - Implement atomic `add_ref`/`release` functions instead of `IMPLEMENT_REFCOUNTING` macro
- **Explicit parameter release** - Must call `release()` on all object parameters in callbacks (memory leak if forgotten)
- **Function pointers** - Use structure fields with `CEF_CALLBACK` functions instead of virtual methods
- **Manual string conversion** - Use `cef_string_from_ascii()` / `cef_string_clear()` instead of `CefString` class
- **Structure initialization** - Use `calloc()` and set function pointers instead of C++ constructors

**See [Using the CAPI](https://chromiumembedded.github.io/cef/using_the_capi) for complete C API patterns and examples.**

## Critical C API Rules

When working with the C API, you **must** follow these rules to avoid crashes and memory leaks:

1. **CEF structure MUST be first member** - Allows safe casting between base and wrapper types
2. **Set `size` to CEF type size** - Use `sizeof(cef_*_t)`, not `sizeof(your_wrapper_t)`
3. **Release all callback parameters** - Except `self`; failure causes memory leaks
4. **Add reference when returning to CEF** - CEF will release when done
5. **Use atomic operations** - Reference counting functions called from any thread

**See [Using the CAPI](https://chromiumembedded.github.io/cef/using_the_capi) for detailed explanations, complete code examples, and reference counting patterns.**

## References

- [CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial) - Architecture overview (uses C++ examples)
- [CEF C API Documentation](https://chromiumembedded.github.io/cef/using_the_capi) - C-specific patterns
- [Original C++ cefsimple](../cefsimple/)

---

### Overview (`tests/ceftests/README.md`)

# CEF Unit Tests

This directory contains the CEF unit test application (`ceftests`) - a comprehensive test suite for validating CEF functionality across all supported platforms.

## Overview

**ceftests** is a Google Test-based unit test application that validates CEF APIs and integration patterns:

- **Comprehensive coverage** - Tests most CEF APIs and features
- **Automated testing** - Runs headlessly for CI/CD integration
- **Cross-platform** - Validates behavior on Windows, Linux, and macOS
- **Multiple modes** - Supports Chrome style and Alloy style browser testing
- **Quality assurance** - Used to verify CEF releases and Chromium updates

### Comparison with cefclient

| Feature | ceftests | cefclient |
|---------|----------|-----------|
| **Purpose** | Automated unit testing | Manual feature demonstration |
| **Test Type** | Google Test (gtest) | Interactive manual tests |
| **Execution** | Headless/automated | GUI-based interactive |
| **Best for** | CI/CD, regression testing | Feature exploration, debugging |

**For testing:** Use ceftests for automated validation and cefclient for manual feature testing and exploration.

## Test Categories

ceftests includes unit tests for:

### Core Features

- **API Version** - CEF version and API hash validation
- **Command Line** - Command-line argument parsing
- **Life Span** - Browser lifecycle and window management
- **Navigation** - URL loading, redirects, and navigation events
- **Frame** - Multi-frame handling and frame lifecycle

### Web Content

- **DOM** - DOM manipulation and queries
- **JavaScript** - V8 integration and JavaScript execution
- **Display** - Rendering and display events
- **Dialogs** - JavaScript dialogs and file dialogs

### Network and Resources

- **URL Request** - Network requests and responses
- **Scheme Handler** - Custom protocol handlers
- **Cookie** - Cookie management and storage
- **CORS** - Cross-origin resource sharing
- **Resource Manager** - Resource loading and caching
- **Certificate Errors** - SSL/TLS certificate handling

### Advanced Features

- **Process Messages** - Inter-process communication
- **Message Router** - JavaScript-C++ messaging framework
- **DevTools** - Chrome DevTools protocol
- **Downloads** - Download handling and management
- **Printing** - Print and print-to-PDF functionality
- **Media Access** - Camera and microphone permissions
- **Audio Output** - Audio device enumeration

### UI and Rendering

- **Views Framework** - CEF Views UI tests (button, panel, textfield, window, scroll view)
- **OSR (Off-Screen Rendering)** - Windowless rendering and accessibility
- **Draggable Regions** - Custom window dragging areas
- **Permission Prompts** - Permission request UI

### Utilities

- **Parser** - URL and data parsing
- **String** - CEF string handling
- **Stream** - Stream operations and handlers
- **Time** - Time conversion utilities
- **Thread** - Threading and task posting
- **Tracing** - Performance tracing integration
- **Waitable Event** - Synchronization primitives
- **XML/ZIP** - XML parsing and ZIP archive handling

## Running Tests

### Basic Usage

Run all tests with default settings:

```bash
# Windows/Linux
ceftests

# macOS
./ceftests.app/Contents/MacOS/ceftests
```

### Common Test Options

Use Google Test flags to control test execution:

```bash
# Run specific test suite
ceftests --gtest_filter="NavigationTest.*"

# Run specific test
ceftests --gtest_filter="NavigationTest.LoadURL"

# Exclude specific tests
ceftests --gtest_filter="-AudioOutputTest.*"

# List all available tests
ceftests --gtest_list_tests

# Run with Chrome style Views framework
ceftests --use-views

# Run with Alloy style
ceftests --use-alloy-style

# Combine options
ceftests --use-views --gtest_filter="NavigationTest.*"
```

### Platform-Specific Notes

**macOS:** Use the path to the executable inside the `.app` bundle:
```bash
./ceftests.app/Contents/MacOS/ceftests --use-views
```

**Linux headless:** Use `xvfb-run` for headless testing:
```bash
xvfb-run ceftests --no-sandbox
```

### Filters for Known Issues

Some tests are known to be flaky or have platform-specific issues. For the recommended test filters that exclude these known issues, see [Chromium Update § Run CEF tests](https://chromiumembedded.github.io/cef/chromium_update#5-run-cef-tests), section C.

## Test Infrastructure

### Core Test Framework

- **test_handler.h/cc** - Base class for browser-based tests
- **test_suite.h/cc** - Test suite initialization and configuration
- **test_util.h/cc** - Common test utilities and helpers
- **routing_test_handler.h/cc** - Base for tests using message routing
- **thread_helper.h/cc** - Threading utilities for async tests
- **track_callback.h** - Callback tracking for verifying execution order

### Test Server Support

- **test_server.h/cc** - HTTP test server implementation
- **test_server_manager.h/cc** - Server instance management
- **test_server_runner.h/cc** - Server execution framework
- **test_server_observer.h/cc** - Server event monitoring

### Platform-Specific Files

- **Windows**: `win/` directory with resources and manifest
- **macOS**: Helper process integration, OS rendering support (`os_rendering_unittest_mac.mm`)
- **Linux**: Resource utilities (`resource_util_linux.cc`)

## Test Development

### Writing New Tests

Tests use Google Test framework with CEF-specific patterns:

```cpp
#include "tests/ceftests/test_handler.h"

TEST(MyTestSuite, MyTest) {
  // Create test handler
  CefRefPtr<MyTestHandler> handler = new MyTestHandler();

  // Execute test
  handler->ExecuteTest();

  // Verify results
  EXPECT_TRUE(handler->succeeded());
}
```

For browser-based tests, extend `TestHandler`:

```cpp
class MyTestHandler : public TestHandler {
 public:
  void RunTest() override {
    // Create and load browser
    CreateBrowser("https://example.com");
  }

  void OnLoadEnd(CefRefPtr<CefBrowser> browser,
                 CefRefPtr<CefFrame> frame,
                 int httpStatusCode) override {
    // Test logic here
    DestroyTest();
  }
};
```

### Test Execution Modes

ceftests supports multiple execution modes:

- **Chrome style** - Tests using Chrome UI layer (default)
- **Alloy style** - Tests using Content API layer (`--use-alloy-style`)
- **Views framework** - Tests using CEF Views (`--use-views`)
- **Headless** - Non-interactive testing for CI/CD (Linux: use `xvfb-run`)

## Known Issues

Some tests may be flaky or have known limitations:

- **Flaky tests** - Tracked at: https://github.com/chromiumembedded/cef/issues?q=is%3Aissue+is%3Aopen+label%3Atests
- **Chrome style limitations** - Tracked at: https://github.com/chromiumembedded/cef/issues?q=is%3Aissue+is%3Aopen+label%3Achrome
- **macOS Views support** - Issue #3188: https://github.com/chromiumembedded/cef/issues/3188

For the latest test filters and workarounds, see the ChromiumUpdate.md Wiki page.

## Resources

Test resources are located in `resources/` directory:

- SSL certificates for certificate validation tests
- Test data files

## References

- [CEF General Usage](https://chromiumembedded.github.io/cef/general_usage) - Complete API documentation
- [Chromium Update](https://chromiumembedded.github.io/cef/chromium_update) - Test execution details
- [Google Test Documentation](https://google.github.io/googletest/) - gtest framework reference
- [cefclient](../cefclient/) - Interactive test application for manual testing

---

### Overview (`tests/shared/README.md`)

# CEF Shared Test Code

This directory contains common code and utilities shared across CEF test applications (cefclient and ceftests).

## Overview

The shared directory provides reusable components that handle common CEF integration patterns, reducing code duplication across test applications and demonstrating best practices for CEF application development.

**Used by:**

- [cefclient](../cefclient/) - Comprehensive feature demonstration and testing application
- [ceftests](../ceftests/) - Automated unit test suite

**Not used by:**

- [cefsimple](../cefsimple/) - Minimal C++ example (self-contained)
- [cefsimple_capi](../cefsimple_capi/) - Minimal C API example (self-contained)

## Directory Structure

### browser/

Browser process utilities including:

- Application framework with delegate pattern (`client_app_browser`)
- Message loop implementations (standard, external pump, multi-threaded)
- Cross-platform resource loading (`resource_util`)
- File system operations and geometry utilities

### common/

Code shared across all process types:

- Base application handler (`client_app`)
- Process type detection and command-line parsing
- Custom scheme registration
- String and binary data utilities

### renderer/

Renderer process handler with delegate pattern for V8 context management and JavaScript extension registration.

### resources/

Shared test resources (HTML pages, icons, sample files).

## Key Concepts

**Delegate Pattern:** Applications (cefclient, ceftests) extend shared base classes by implementing delegates rather than modifying shared code.

**Message Loop Abstraction:** Supports multiple threading models - standard CEF loop, external pump (integrates with platform event loops), and multi-threaded mode.

**Platform Abstraction:** Common interfaces with platform-specific implementations for resource loading, file operations, and window management.

## Usage

Applications use shared handlers for process-specific behavior:

```cpp
CefRefPtr<ClientApp> app;
switch (process_type) {
  case ClientApp::BrowserProcess:
    app = new ClientAppBrowser();   // Browser process handler
    break;
  case ClientApp::RendererProcess:
    app = new ClientAppRenderer();  // Renderer process handler
    break;
}
```

Applications customize behavior by implementing delegates without modifying shared code.

## References

- [CEF General Usage](https://chromiumembedded.github.io/cef/general_usage) - CEF API documentation
- [CEF Tutorial](https://chromiumembedded.github.io/cef/tutorial) - Application architecture overview
- [cefclient](../cefclient/) - Reference implementation using shared code
- [ceftests](../ceftests/) - Test suite using shared code

---

### Overview (`tools/cefbuilds/README.md`)

# CEF Builds JSON Tools

Tools for generating and maintaining the JSON index files used by the
[CEF Builds](https://cef-builds.spotifycdn.com/index.html) CDN and the CEF
installer.

## Files

### Core libraries

- **`cef_json_builder.py`** — Builds and maintains the master `index.json` file
  that contains the full catalog of CEF binary distributions across all
  platforms, versions, and channels. Handles file metadata (name, size, sha1,
  last_modified), Chromium version mapping, and sandbox compatibility hashes.

- **`cef_installer_builder.py`** — Generates installer-optimized CDN query files
  from a populated `cef_json_builder` instance. Produces lightweight JSON files
  designed for efficient HTTP HEAD timestamp checks by the CEF installer.

### Data files

- **`revoked.json`** — Manually maintained list of revoked CEF versions. Revoked
  versions are excluded from all installer-generated JSON output. The installer
  also fetches this file from the CDN and refuses to install any listed version.

### Examples and tests

- **`cef_json_builder_example.py`** — Example script demonstrating
  `cef_json_builder` usage. Creates and updates a local `index.json` with fake
  file data.

- **`cef_json_builder_test.py`** — Unit tests for `cef_json_builder`.

- **`cef_installer_builder_test.py`** — Unit tests for `cef_installer_builder`.

## CDN file formats

### Master index

- **`index.json`** — Full data index of all CEF binary distributions. Generated
  by `cef_json_builder`. Keyed by platform, with version records sorted
  newest-first by file last_modified timestamp.

### Installer query files

Generated by `cef_installer_builder` from the master index:

- **`stable.txt`** — Current stable milestone number (e.g., `137`).

- **`{milestone}.json`** (e.g., `137.json`) — Newest build per platform for a
  given milestone. Used by the installer to check if an update is available.

- **`{milestone}_{platform}.json`** (e.g., `137_windows64.json`) — All builds
  for a milestone+platform combination, sorted newest-first.

- **`{abi_hash}_{platform}.json`** (e.g., `abc123def4567890_windows64.json`) —
  All builds compatible with a given ABI hash and platform across all milestones,
  sorted newest-first. Windows platforms only (tied to `chrome_elf.dll` /
  Chromium sandbox ABI).

## Concepts

### Platforms

Supported platforms: `linux32`, `linux64`, `linuxarm`, `linuxarm64`,
`macosarm64`, `macosx64`, `windows32`, `windows64`, `windowsarm64`.

### Distribution types

Each version may have files of these types: `standard`, `minimal`, `client`,
`tools`, `release_symbols`, `debug_symbols`, `signed`.

The `signed` type contains code-signed archives with catalog files, used by the
installer for verified installation.

### Channels

Versions belong to either the `stable` or `beta` channel.

### Version formats

- **New-style**: `137.3.5+g62d140e+chromium-137.0.7204.6`
  - Short version: `137.3.5` (everything before the first `+`)
  - Milestone: `137` (major version number)
- **Old-style**: `3.2704.1414.g185cd6c` (predates the installer format)

### ABI hash (`sandbox_compat`)

A 16-character hex string identifying the Windows sandbox ABI compatibility
level. Derived from `cef_api_versions.json` on GitHub. Versions sharing the same
ABI hash can use the same `chrome_elf.dll` and are interchangeable from the
sandbox's perspective.

### Revocation

The `revoked.json` file lists versions that must not be installed. When passed
to `cef_installer_builder`, revoked versions are automatically excluded from
all generated output. The installer also fetches this file from the CDN at
runtime and refuses to install any listed version.

Entries can revoke a single version or a range of versions:

```json
{
  "revoked_versions": [
    {
      "version": "137.1.0",
      "reason": "CVE-2024-XXXXX: critical sandbox escape",
      "revoked_at": "2024-01-15T00:00:00Z"
    },
    {
      "version_min": "138.0.0",
      "version_max": "138.2.99",
      "reason": "CVE-2024-YYYYY: affects all 138.0–138.2 builds",
      "revoked_at": "2024-02-01T00:00:00Z"
    }
  ]
}
```

**Single version** (point revocation):
- `version` — Short version string (e.g., `137.1.0`).

**Version range** (inclusive):
- `version_min` — Inclusive lower bound (e.g., `138.0.0`).
- `version_max` — Inclusive upper bound (e.g., `138.2.99`).

**Common fields:**
- `reason` — Human-readable explanation (CVE ID, bug reference, etc.).
- `revoked_at` — ISO 8601 timestamp of when the revocation was added.

A single-version entry using `version` is equivalent to setting both
`version_min` and `version_max` to the same value. If both `version` and
`version_min`/`version_max` are present, the range fields take precedence.

## Running tests

```bash
cd cef/tools/cefbuilds
python3 -m unittest cef_json_builder_test -v
python3 -m unittest cef_installer_builder_test -v
```

---

### Overview (`tools/clang/README.md`)

# CEF Clang Tools

This directory contains clang-based tools for CEF code modernization and refactoring.

## Tools

### cef_cpp_rewriter

A clang AST-based rewriter tool for automating C++20 modernization of CEF code.

**Supported transformations:**

- `.contains()` for associative containers
- Structured bindings for range-for loops
- Iterator loops to range-for
- DISALLOW_COPY_AND_ASSIGN replacement

See [TRANSFORMS.md](TRANSFORMS.md) for complete documentation of all transformations, command-line flags, and examples.

## Prerequisites

- Chromium checkout with CEF
- **Python 3.10+** (Chromium's build scripts require it)
- ~30 minutes for initial clang bootstrap

**Note:** CEF is a separate git repository within chromium/src. Chromium's clang
tool scripts (`run_tool.py`, `test_tool.py`, `apply_edits.py`) use git commands
that don't work across repository boundaries. This directory provides CEF-specific
replacements: `run_tool.py`, `test_tool.py`, and `apply_edits.py`.

### Python Version

macOS ships with Python 3.9 which is too old. Install Python 3.12 via Homebrew:

```bash
brew install python@3.12
ln -s /opt/homebrew/opt/python@3.12/bin/python3.12 /opt/homebrew/opt/python@3.12/bin/python3
export PATH="/opt/homebrew/opt/python@3.12/bin:$PATH"
python3 --version  # Should show 3.12.x
```

Add the export line to `~/.zshrc` to make it permanent.

## Quick Start

### Initial Setup (one-time, ~30 minutes)

```bash
# From chromium/src directory
./cef/tools/clang/scripts/build_clang_rewriter.sh
```

This will:

1. Create a symlink from `tools/clang/cef_cpp_rewriter` to the CEF tool
2. Bootstrap clang with the tool (~30 minutes)

**Warning:** The clang bootstrap updates `third_party/llvm-build/`, which will
invalidate all existing Chromium/CEF build directories and trigger a full
rebuild the next time you build. Plan accordingly.

### Running the Tool

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Tool Arguments

The `--tool-args` option passes arguments directly to `cef_cpp_rewriter`.
See [TRANSFORMS.md](TRANSFORMS.md) for the complete list of command-line flags.

**Examples:**
```bash
# Run only iterator-loops transformation
--tool-args="--only=iterator-loops"

# Run only contains and structured-bindings
--tool-args="--only=contains,structured-bindings"

# Disable specific transformation (all others still run)
--tool-args="--contains=false"
```

### Incremental Rebuilds

After modifying `CefCppRewriter.cpp`, rebuild quickly with:

```bash
ninja -C third_party/llvm-build/Release+Asserts cef_cpp_rewriter
```

**Do not re-run `build_clang_rewriter.sh`** - it rebuilds everything from scratch.

## Testing

```bash
# Run tool tests
python3 cef/tools/clang/scripts/test_tool.py cef_cpp_rewriter

# With verbose output
python3 cef/tools/clang/scripts/test_tool.py cef_cpp_rewriter --verbose
```

## Compatibility

CEF targets C++20. See [TRANSFORMS.md](TRANSFORMS.md) for minimum toolchain versions.

## Standalone Distribution

The tool can be packaged for use on any C++ project (not just CEF):

```bash
# Package to a target directory
./cef/tools/clang/scripts/package_standalone.sh /path/to/target

# This creates:
# /path/to/target/
# ├── bin/cpp_rewriter           # The tool binary
# ├── lib/clang/<version>/       # Bundled clang headers
# ├── scripts/
# │   ├── run_rewriter.py        # Standalone wrapper
# │   ├── apply_edits.py
# │   └── process_edits.py
# └── README.md
```

The standalone distribution is self-contained and includes bundled clang headers
so it works without requiring a matching system clang installation.

**Usage on any CMake project:**
```bash
cd my-project

# Generate compile_commands.json (requires Ninja or Makefiles generator)
cmake -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -B build

# Run the rewriter
/path/to/target/scripts/run_rewriter.py -p build src/ \
  | /path/to/target/scripts/apply_edits.py --base-dir build
```

See `standalone/README.md` for complete standalone usage documentation.

## Directory Structure

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Maintenance

This tool is not regularly tested. It may need updates when:

| Trigger | Likely Fix |
|---------|------------|
| Chromium updates `tools/clang/` infrastructure | Update `CMakeLists.txt`, check `build.py` flags |
| LLVM/Clang API changes | Update AST matcher syntax, check deprecations in Clang doxygen |
| CEF adopts C++23 | Add `flat_map`/`flat_set` container types to matcher |
| Build fails after Chromium update | Compare with current `tools/clang/ast_rewriter/` example |

### Diagnosing Build Failures

If the tool fails to build after a Chromium update:

1. Check if `ast_rewriter` still exists and builds:
    ```bash
    python3 tools/clang/scripts/build.py --bootstrap --extra-tools ast_rewriter
    ```

2. Compare CMakeLists.txt with the current ast_rewriter version:
    ```bash
    diff cef/tools/clang/cef_cpp_rewriter/CMakeLists.txt tools/clang/ast_rewriter/CMakeLists.txt
    ```

3. Check for API changes in Clang's AST matchers (review Clang release notes)

### Cleanup

After running the tool, you may want to remove the symlink:

```bash
rm tools/clang/cef_cpp_rewriter  # Removes symlink only, not CEF source
```

## Resources

- Chromium clang tool documentation: `docs/clang_tool_refactoring.md`
- Chromium example: `tools/clang/ast_rewriter/`
- [AST Matcher Reference](https://clang.llvm.org/docs/LibASTMatchersReference.html)
- [LibTooling Tutorial](https://clang.llvm.org/docs/LibASTMatchersTutorial.html)

---

### Overview (`tools/claude/README.md`)

# Tools and Detailed Instructions for CEF Development

This directory contains tools and detailed instructions for using coding
agents to assist with CEF (Chromium Embedded Framework) development. Use these
guides with models that benefit from explicit workflows, examples, and
verification steps, including Claude Opus 4.x and GPT Terra.

The guides were originally written for Claude Code and retain their `CLAUDE_*`
filenames. Other coding agents can use them directly; adapt any Claude-specific
setup or file attachment syntax to your agent. For GPT Sol or other frontier
models that work well with concise instructions, see the
[GPT guides](../gpt/README.md) for concise patch and build instructions and
example prompts. For other tasks, newer frontier models can often discover the
relevant details themselves, using the detailed instruction files here as
reference material when needed.

***
[TOC]
***

## Quick Navigation

**Are you updating CEF to a new Chromium version?**

→ See [CHROMIUM_UPDATE.md](CHROMIUM_UPDATE.md) for the complete workflow:

- Fixing patches that fail to apply
- Fixing build errors from API changes
- Using analyzer scripts and verification tools

**Are you developing a CEF application using a binary distribution?**

→ See [CLIENT_DEVELOPMENT.md](CLIENT_DEVELOPMENT.md) for implementing features:

- Adding custom URL schemes
- JavaScript-to-C++ communication
- Network request interception
- Popup window customization

**Are you writing or debugging CEF unit tests?**

→ See [CLAUDE_TEST_INSTRUCTIONS.md](CLAUDE_TEST_INSTRUCTIONS.md) for working with ceftests:

- Running existing unit tests
- Creating new tests for CEF features
- Debugging test failures and flakiness
- Using TestHandler, RoutingTestHandler, and TestServer

**Are you developing libcef internals (CEF implementation code)?**

→ See [CLAUDE_LIBCEF_INSTRUCTIONS.md](CLAUDE_LIBCEF_INSTRUCTIONS.md) for libcef development patterns:

- Adding new CEF APIs with proper versioning
- Implementing WebContentsDelegate callbacks
- Working with Chrome and Alloy browser styles
- Finding and fixing NOTIMPLEMENTED() stubs

**Are you syncing CEF base headers with Chromium?**

→ See [CLAUDE_BASE_SYNC_INSTRUCTIONS.md](CLAUDE_BASE_SYNC_INSTRUCTIONS.md) for synchronizing `cef/include/base/` headers:

- CEF-specific modifications (namespaces, includes, platform macros)
- Files to sync vs files to preserve
- Handling C++23 reverts
- Step-by-step sync process

**Are you cherry-picking commits from upstream CEF?**

→ See [CLAUDE_CHERRY_PICK_INSTRUCTIONS.md](CLAUDE_CHERRY_PICK_INSTRUCTIONS.md) for cherry-picking commits that include patch files:

- Extracting and applying source file changes from patches
- Resaving patches with correct index hashes
- Handling multiple patch files per commit
- Recovery when things go wrong

**Are you applying a Chromium commit to CEF as a patch?**

→ See [CLAUDE_SRC_PATCH_INSTRUCTIONS.md](CLAUDE_SRC_PATCH_INSTRUCTIONS.md) for creating or updating CEF patches from Chromium commits:

- Creating new patch files and adding to patch.cfg
- Adding changes to existing patch files
- Handling version differences between Chromium versions
- Verifying patches can be reverted and reapplied

**Are you improving unit test coverage?**

→ See [CLAUDE_COVERAGE_INSTRUCTIONS.md](CLAUDE_COVERAGE_INSTRUCTIONS.md) for running and analyzing code coverage:

- Human prerequisites for setting up coverage builds
- Building and running tests with coverage instrumentation
- Analyzing coverage reports to identify gaps
- Workflow for improving function and line coverage

## Files in This Directory

### Documentation

- **[CHROMIUM_UPDATE.md](CHROMIUM_UPDATE.md)** - Complete guide for updating CEF to new Chromium versions
- **[CLAUDE.md.in](CLAUDE.md.in)** - Template for root CLAUDE.md (copied by setup_claude.py)
- **[CLAUDE_BASE_SYNC_INSTRUCTIONS.md](CLAUDE_BASE_SYNC_INSTRUCTIONS.md)** - Instructions for syncing CEF base headers with Chromium
- **[CLAUDE_BUILD_INSTRUCTIONS.md](CLAUDE_BUILD_INSTRUCTIONS.md)** - Detailed instructions for Claude agents fixing build errors
- **[CLAUDE_CHERRY_PICK_INSTRUCTIONS.md](CLAUDE_CHERRY_PICK_INSTRUCTIONS.md)** - Instructions for cherry-picking commits from upstream CEF that include patch files
- **[CLAUDE_CLIENT_INSTRUCTIONS.md](CLAUDE_CLIENT_INSTRUCTIONS.md)** - Detailed instructions for Claude agents implementing features in CEF applications
- **[CLAUDE_COVERAGE_INSTRUCTIONS.md](CLAUDE_COVERAGE_INSTRUCTIONS.md)** - Instructions for running and analyzing code coverage
- **[CLAUDE_LIBCEF_INSTRUCTIONS.md](CLAUDE_LIBCEF_INSTRUCTIONS.md)** - Detailed instructions for Claude agents developing libcef internals (API versioning, WebContentsDelegate)
- **[CLAUDE_PATCH_INSTRUCTIONS.md](CLAUDE_PATCH_INSTRUCTIONS.md)** - Detailed instructions for Claude agents fixing patch failures
- **[CLAUDE_SRC_PATCH_INSTRUCTIONS.md](CLAUDE_SRC_PATCH_INSTRUCTIONS.md)** - Instructions for applying Chromium commits to CEF as new or existing patches
- **[CLAUDE_TEST_INSTRUCTIONS.md](CLAUDE_TEST_INSTRUCTIONS.md)** - Detailed instructions for Claude agents creating and running CEF unit tests
- **[CLAUDE_WIKI_INSTRUCTIONS.md](CLAUDE_WIKI_INSTRUCTIONS.md)** - Bitbucket wiki formatting guidelines for Claude agents
- **[CLIENT_DEVELOPMENT.md](CLIENT_DEVELOPMENT.md)** - Complete guide for CEF client application development
- **[README.md](README.md)** - This file

### Python Tools

- **[analyze_build_output.py](analyze_build_output.py)** - Analyze and format ninja build output with error index
- **[analyze_coverage_output.py](analyze_coverage_output.py)** - Analyze LLVM coverage reports and identify coverage gaps
- **[analyze_patch_output.py](analyze_patch_output.py)** - Analyze and format `patch_updater.py` output with file movement detection
- **[patch_utils.py](patch_utils.py)** - Shared utilities for patch analysis tools (file movement detection)
- **[verify_patch.py](verify_patch.py)** - Verify that regenerated patches include all changes from reject files
- **[format_wiki.py](format_wiki.py)** - Apply Bitbucket wiki formatting guidelines to markdown files (supports wildcards; also integrated into `../fix_style.py`)

### Test Files

- **[analyze_build_output_test.py](analyze_build_output_test.py)** - Unit tests for analyze_build_output.py
- **[analyze_coverage_output_test.py](analyze_coverage_output_test.py)** - Unit tests for analyze_coverage_output.py
- **[analyze_patch_output_test.py](analyze_patch_output_test.py)** - Unit tests for analyze_patch_output.py
- **[patch_utils_test.py](patch_utils_test.py)** - Unit tests for patch_utils.py
- **[verify_patch_test.py](verify_patch_test.py)** - Unit tests for verify_patch.py
- **[format_wiki_test.py](format_wiki_test.py)** - Unit tests for format_wiki.py

## Common Setup

For Chromium update workflows, run the setup script:

```bash
cd chromium/src/cef/tools
python3 setup_claude.py
```

This copies `CLAUDE.md.in` to the project root as `chromium/src/CLAUDE.md`, enabling Claude Code to understand the Chromium/CEF codebase structure.

## Formatting Files

The `fix_style.py` tool in `//cef/tools/` formats C/C++, Python, and Markdown files:

```bash
# From chromium/src/cef/tools directory:

# Format single markdown file
python3 fix_style.py claude/CLAUDE_TEST_INSTRUCTIONS.md

# Format all CLAUDE instruction files
python3 fix_style.py claude/CLAUDE_*.md

# Format all markdown files in claude directory
python3 fix_style.py claude/*.md

# Format all staged files (including markdown)
python3 fix_style.py staged
```

The markdown formatter applies [Bitbucket wiki formatting guidelines](CLAUDE_WIKI_INSTRUCTIONS.md) (blank lines before lists, 4-space indentation, etc.).

## Tips for Working with Claude Code

These tips apply to both Chromium updates and client development:

### 1. Provide Context

Always include relevant version numbers or distribution details:

**For Chromium updates:**
```
Old version: 139.0.7258.0
New version: 140.0.7339.0
```

**For client development:**
```
CEF binary distribution: cef_binary_142.0.10+g29548e2+chromium-142.0.7444.135_macosarm64
```

### 2. Attach Relevant Files

Use `@filename` to attach files Claude should read:

- `@cef/tools/claude/patch_analysis.txt` - Analyzed patch output
- `@cef/tools/claude/build_analysis.txt` - Analyzed build output
- `@cef/tools/claude/CLAUDE_CHERRY_PICK_INSTRUCTIONS.md` - Cherry-picking upstream commits
- `@cef/tools/claude/CLAUDE_CLIENT_INSTRUCTIONS.md` - Client development guide
- `@cef/tools/claude/CLAUDE_SRC_PATCH_INSTRUCTIONS.md` - Applying Chromium commits as patches
- `@cef/tools/claude/CLAUDE_TEST_INSTRUCTIONS.md` - CEF unit testing guide

**Tip:** In large directory structures like `chromium/src`, the `@` syntax can be slow. Use `//` syntax for workspace-relative paths instead (e.g., `//cef/tools/claude/patch_analysis.txt`).

### 3. Let Claude Work Systematically

Don't interrupt mid-stream unless necessary. Claude will:

- Create TODO lists
- Work through items one by one
- Report progress regularly
- Ask for help when stuck

### 4. Use Incremental Prompts

For large tasks, you can guide Claude incrementally:

**For Chromium updates:**
```
1. "Start fixing patches using @CLAUDE_PATCH_INSTRUCTIONS.md"
2. [Claude works for a while]
3. "Good progress. Continue with the remaining patches."
4. [Claude finishes]
5. "Now let's fix build errors using @CLAUDE_BUILD_INSTRUCTIONS.md"
```

**For unit testing:**
```
1. "Create tests for the new feature using @CLAUDE_TEST_INSTRUCTIONS.md"
2. [Claude creates tests]
3. "Run the tests and fix any failures"
4. [Claude debugs and fixes]
5. "Good, now verify they work in both Chrome and Alloy styles"
```

### 5. Ask for Summaries

After a session:
```
Please summarize all the changes you made, organized by category.
```

Claude can provide a detailed summary for documentation or commit messages.

### 6. Use the Analyzers Proactively

For Chromium updates, run the analyzers yourself first to understand the scope:

**For patches:**
```bash
# From chromium/src/cef/tools/claude directory:
python3 analyze_patch_output.py patch_output.txt \
  --old-version 139.0.7258.0 \
  --new-version 140.0.7339.0 \
  --no-color > patch_analysis.txt
```

**For build errors:**
```bash
# From chromium/src/cef/tools/claude directory:
python3 analyze_build_output.py build_output.txt \
  --old-version 139.0.7258.0 \
  --new-version 140.0.7339.0 \
  --no-color > build_analysis.txt
```

Then share the analysis files with Claude.

## Getting Help

### For Issues with Tools

- Check the guide files and instruction files listed above for usage examples
- Check analyzer script help: `python3 analyze_patch_output.py --help`

### For Issues with CEF

- CEF wiki: https://github.com/chromiumembedded/cef/blob/master/docs/README.md
- CEF forums: https://magpcss.org/ceforum/
- CEF issue tracker: https://github.com/chromiumembedded/cef/issues

### For Issues with Claude Code

- Claude Code documentation: https://docs.claude.com/claude-code
- Improve prompts with more context and specific examples
- Break large tasks into smaller, more manageable pieces

## Contributing

If you improve these tools or instructions:

1. Test with a real Chromium update, client development task, or unit testing workflow
2. Document what you changed and why
3. Update the appropriate guide ([CHROMIUM_UPDATE.md](CHROMIUM_UPDATE.md), [CLIENT_DEVELOPMENT.md](CLIENT_DEVELOPMENT.md), or [CLAUDE_TEST_INSTRUCTIONS.md](CLAUDE_TEST_INSTRUCTIONS.md))
4. Share improvements with the CEF community

## License

These tools are part of the CEF project and follow the same license as CEF (BSD license).

---

### Overview (`tools/gpt/README.md`)

# GPT Instructions for CEF Updates

Use these guides when asking a coding agent to update CEF patches or fix build
errors during a Chromium update. The GPT guides give Sol a short overview of
what to do and how to verify the result. They link to the existing Claude
guides for detailed commands, examples, and troubleshooting.

## Choosing a model

| Model | Starting effort | Guides to use |
| --- | --- | --- |
| GPT-6.1 Sol | Low | The GPT guides in this directory |
| GPT-5.6 Terra | Choose for your task | The Claude guides in `cef/tools/claude/` |

For Sol, start with low effort and use the Sol examples below. The agent can
consult the linked Claude guides as it works. For Terra, use the Terra examples,
which point directly to the detailed Claude guides. Those guides work with
other models despite their filenames.

Select the model and effort in your coding agent before sending the prompt.
The instruction files describe the work; model selection is a separate setting.

These recommendations are a starting point for trying the workflows on real
updates. Adjust the GPT model and reasoning effort to balance speed and cost
while meeting the same completion checks. Check whether the agent covers every
failed file, preserves CEF behavior, and saves source fixes into the patches.
If Sol gets stuck on a particular issue or cannot explain why a behavioral
change is correct, try that issue again at medium effort. When comparing speed
and cost, include any follow-up work needed to correct the result.

## Getting started

Before launching the agent, use the existing Chromium update guide to prepare
your checkout and the analysis for the phase you're working on:

1. Review the [complete update workflow](../claude/CHROMIUM_UPDATE.md#complete-update-workflow)
   for the order of checkout updates, patch repairs, builds, and testing.
2. Check the [prerequisites](../claude/CHROMIUM_UPDATE.md#prerequisites) and
   [setup](../claude/CHROMIUM_UPDATE.md#setup): you'll need a Chromium checkout
   with CEF integration, Python 3, and the appropriate build configuration.
   The `setup_claude.py` step installs context for Claude Code; it is not a
   prerequisite for using the GPT prompts.
3. For patch repairs, follow [Phase 1: Fixing Patches](../claude/CHROMIUM_UPDATE.md#phase-1-fixing-patches)
   to capture `patch_updater.py` output and generate `patch_analysis.txt` with
   your old and new Chromium versions. Then use the patch prompt below.
4. Once the patches apply cleanly, follow [Phase 2: Fixing Build Errors](../claude/CHROMIUM_UPDATE.md#phase-2-fixing-build-errors)
   to capture a build of your chosen target and generate `build_analysis.txt`.
   Then use the build prompt below.

Start your coding agent from the `chromium/src` checkout root. Copy one of the
complete prompts below, then replace the Chromium versions and analysis path
with yours. For a build task, also set your output directory and build target.
All paths in the prompts are relative to `chromium/src`.

Use the analysis files produced by the existing tools in `cef/tools/claude/`:

- `patch_analysis.txt` lists failed patches and files.
- `build_analysis.txt` lists build errors and points to the relevant sections
  of `build_output.txt`.

The build examples include permission to fix Chromium files outside `cef/`
when custom CEF patches cause their build failures. Keep that instruction if
it applies to your update: it tells the agent to save those fixes into the
associated CEF patches and overrides the detailed build guide's usual scope.

## Example prompts for Sol at low effort

### Update patches

```text
Work from the chromium/src checkout root; all paths below are relative to it.

Please update patches from 154.0.8037.0 to 156.0.8078.0
Read and follow the instructions in:
cef/tools/gpt/GPT_PATCH_INSTRUCTIONS.md
When a patch has multiple failed files you MUST check all of the files.

Here's the patch output analysis: cef/tools/claude/patch_analysis.txt
```

### Fix build errors

```text
Work from the chromium/src checkout root; all paths below are relative to it.

Please fix build errors for the 154.0.8037.0 to 156.0.8078.0 update
Read and follow the instructions in:
cef/tools/gpt/GPT_BUILD_INSTRUCTIONS.md

Build output directory: out/Debug_GN_arm64
Build target: cef

IMPORTANT: Some .cc files outside of cef may also have build errors after
the Chromium update, due to the custom CEF patches applied. Fix those build
errors and re-save the associated CEF patch files using
cef/tools/gpt/GPT_PATCH_INSTRUCTIONS.md.

Here's the build error analysis: cef/tools/claude/build_analysis.txt

IMPORTANT: Do not try to read all of cef/tools/claude/build_output.txt. Use
the positional markers from cef/tools/claude/build_analysis.txt to read
relevant sections ONLY.
```

## Example prompts for Terra

### Update patches

```text
Work from the chromium/src checkout root; all paths below are relative to it.

Please update patches from 154.0.8037.0 to 156.0.8078.0
Read and follow the instructions in:
cef/tools/claude/CLAUDE_PATCH_INSTRUCTIONS.md
When a patch has multiple failed files you MUST check all of the files.

Here's the patch output analysis: cef/tools/claude/patch_analysis.txt
```

### Fix build errors

```text
Work from the chromium/src checkout root; all paths below are relative to it.

Please fix build errors for the 154.0.8037.0 to 156.0.8078.0 update
Read and follow the instructions in:
cef/tools/claude/CLAUDE_BUILD_INSTRUCTIONS.md

Build output directory: out/Debug_GN_arm64
Build target: cef

IMPORTANT: Some .cc files outside of cef may also have build errors after
the Chromium update, due to the custom CEF patches applied. You should also
fix those build errors and re-save the associated CEF patch files using
cef/tools/claude/CLAUDE_PATCH_INSTRUCTIONS.md. This extends the build
guide's default restriction to files under cef.

Here's the build error analysis: cef/tools/claude/build_analysis.txt

IMPORTANT: Do not try to read all of cef/tools/claude/build_output.txt. Use
the positional markers from cef/tools/claude/build_analysis.txt to read
relevant sections ONLY.
```

---

### Overview (`libcef_dll/bootstrap/installer/README.md`)

# CEF Installer Library

The CEF Installer Library provides automatic CEF version management for
applications using the bootstrap architecture. It handles downloading,
installing, updating, and uninstalling CEF from a shared installation
directory.

## Contents

- [Client Integration](#client-integration)
- [Command-Line Options](#command-line-options)
- [Background Update API](#background-update-api)
- [How It Works](#how-it-works)
  - [Automatic Installation](#automatic-installation)
  - [Uninstall execution and outcomes](#uninstall-execution-and-outcomes)
  - [Enterprise Policy](#enterprise-policy)
  - [Download Source Precedence and Robustness](#download-source-precedence-and-robustness)
  - [Shared Installation Directory](#shared-installation-directory)
  - [Version Selection](#version-selection)
  - [Unchecked CEF Path](#unchecked-cef-path)
- [Progress Notifications](#progress-notifications)
  - [Cancellation via Parent Window](#cancellation-via-parent-window)
  - [Parent Window Handle](#parent-window-handle-cross-process-security)
- [Exit Codes](#exit-codes)
- [Concurrent Access](#concurrent-access)
  - [Protecting a version that is in use](#protecting-a-version-that-is-in-use)
  - [Publishing changes safely](#publishing-changes-safely)
  - [Index recovery and existing destinations](#index-recovery-and-existing-destinations)
  - [Lock waits and failure behavior](#lock-waits-and-failure-behavior)
- [Version Pruning](#version-pruning)
- [Explicit Registration Retention](#explicit-registration-retention)
  - [Recommended workflow](#recommended-workflow)
  - [Eligible stores](#eligible-stores)
  - [Age and launch evidence](#age-and-launch-evidence)
  - [How retention runs](#how-retention-runs)
  - [Availability warning](#availability-warning)
- [Launch Health Tracking](#launch-health-tracking)
  - [Launch-state files](#launch-state-files)
  - [Mode Classification](#mode-classification)
  - [Rollback Behavior](#rollback-behavior)
  - [Cleanup Strategy](#cleanup-strategy)
  - [Stale File GC](#stale-file-gc)
  - [Pruning Protection](#pruning-protection)
  - [Post-Exit Pruning](#post-exit-pruning)
- [Security](#security)
  - [Code Signing](#code-signing)
  - [Config Security](#config-security)
  - [Enterprise Provisioning](#enterprise-provisioning)
  - [Standalone Mode Security](#standalone-mode-security)
  - [Sandbox Compatibility](#sandbox-compatibility)
- [Build Integration](#build-integration)
- [Testing](#testing)
- [Troubleshooting](#troubleshooting)

## Client Integration

### Prerequisites

The installer downloads and verifies signed Release builds of CEF. For
loading to succeed, your application **must**:

1. **Use a Release build of `bootstrap.exe`** — the installer downloads (or your
   application bundles) signed Release CEF binaries, and sandbox initialization
   is not compatible between Debug and Release binaries.
2. **Code sign `chrome_elf.dll`** (which ships next to the exe) with the **same
   certificate** as the exe. The bootstrap verifies that both binaries share the
   same primary thumbprint at startup.

### 1. Embed Installer Configuration

Add a `CEF_INSTALLER_CONFIG` resource to your client DLL's `.rc` file (or to the
bootstrap `.exe`'s `.rc` file — as a fallback when the client DLL has no config,
or for standalone mode; see [Standalone Mode
Security](#standalone-mode-security)):

```rc
CEF_INSTALLER_CONFIG RCDATA "installer_config.json"
```

Create `installer_config.json` with your application's requirements:

```json
{
  "appid": "A3B9C4D5-E6F7-4A8B-9C0D-E1F2A3B4C5D6",
  "vmin": "151.1",
  "vmax": "",
  "abi_hash": "1234567890ABCDEF",
  "launch_health": "explicit"
}
```

For production builds, generate this resource from a template so `vmin` and
`abi_hash` stay synchronized with the bootstrap. See
[Build Integration](#build-integration).

### 2. Configuration Fields

| Field | Required | Description |
|-------|----------|-------------|
| `appid` | Yes | Unique UUID for your application. Never changes once assigned. |
| `vmin` | Yes | Minimum CEF version (e.g., `"151.1"` or `"151.2.1"`). |
| `vmax` | No | Maximum CEF version. Empty string means no upper bound. |
| `abi_hash` | No | Sandbox compatibility hash (16 hex chars). Must match `CEF_SANDBOX_COMPAT_HASH` from `cef_version.h`. Required for sandbox support. |
| `channel` | No | Manifest channel used for downloads: `""` (stable, default) or `"beta"`. Installed versions are channel-agnostic; see [Version Selection](#version-selection). |
| `launch_health` | No | Local launch-health mode: `"off"` (default), `"explicit"` (recommended), or `"exit_code"` (zero-code-change opt-in). |
| `enable_explicit_modes` | No | Enable explicit installer commands (`/cef-update`, `/cef-uninstall`, and `/cef-retention-*`) and standalone auto-install. Default `false`. Only read from the bootstrap `.exe`'s embedded resource. See [Standalone Mode Security](#standalone-mode-security). |
| `unchecked_cef_path` | No | Path to a directory containing `libcef.dll`, used as-is without version, ABI, or signature checks. Relative paths are resolved against the client DLL directory. Only read from the client DLL's embedded resource; ignored in the bootstrap resource. See [Unchecked CEF Path](#unchecked-cef-path). |
| `bundled_cef_path` | No | Path to a pre-extracted CEF distribution directory (must contain `cef_version.json`, `catalog.cat`, and `Release/libcef.dll`). Participates in version selection (newer wins, installed wins ties, revocation demotion). Relative paths are resolved against the client DLL directory. Only read from the client DLL's embedded resource and `RunInstaller` JSON; ignored in the bootstrap resource. See [Version Selection](#version-selection). |
| `install_path` | No | Exclusive installer-state namespace. Relative values are resolved against the client DLL directory. Only read from the client DLL's embedded resource; bootstrap resources cannot set it. `RunInstaller` JSON has an independent operation-specific field. |
| `cdn_urls` | No | One through three ordered HTTPS base URLs for the selected application config. Accepted from client and bootstrap resources; the selected source replaces rather than merges with fallback sources. When omitted, source resolution falls through. See [Download Source Precedence and Robustness](#download-source-precedence-and-robustness). |

Unrecognized configuration keys emit one warning per key and are otherwise
ignored. They never make an otherwise valid configuration fail, preserving
forward compatibility when one config is consumed by different bootstrap
versions.

**Version Clamping:** The `vmin` value is automatically clamped to the
bootstrap's compile-time API version. This prevents the installer from
downloading a CEF version older than what the bootstrap was built against,
which could cause compatibility issues. For example, if you specify
`vmin: "150.0"` but the bootstrap was built with CEF API version 15101, the
effective minimum becomes `"151.1"`. This is particularly relevant for
CMake/Bazel builds where `vmin` may be manually configured.

If clamping makes the range empty, configuration fails immediately with exit
code 100. For example, `vmin: "150.0", vmax: "151.0"` with an API 15101
bootstrap reports the configured minimum, effective minimum (`151.1`),
bootstrap API version, and configured maximum. It is not reported as the
transient no-matching-version error 103.

**Note:** CEF automatically loads resources (.pak files) and locales from
the `Release/` subdirectory where `libcef.dll` resides. No `CefSettings`
configuration is required when using the installer.

#### Maximum Version Guidance

Production configurations should generally cap `vmax` at the newest Chromium
milestone the application has tested. Major Chromium upgrades can require
application-specific compatibility work. For example, `"151.99"` accepts
versions through the literal, inclusive 151.99 bound while excluding 151.100
and Chromium 152 or later. Raise the ceiling deliberately after validating the
next milestone.

## Command-Line Options

Archive extraction uses Chromium's available-memory estimate when selecting
parallel extraction. `--enable-low-end-device-mode` can reduce that estimate
and cause extraction to fall back to single-threaded streaming.

When the bootstrap executable is run with these flags, it enters installer mode:

| Flag | Description |
|------|-------------|
| `/cef-update` | Check for and install CEF updates. |
| `/cef-uninstall` | Unregister application and prune unused CEF versions. |
| `/cef-retention-dry-run` | Report stale registrations and affected versions without modifying installer state. |
| `/cef-retention-apply` | Recompute and apply registration retention under the writer lock. |
| `/cef-max-age-days=<90..3650>` | Retention-only age threshold. Default: 180 days. |
| `/cef-forcecheck` | Force CDN check even if cache is fresh (use with `/cef-update`). |
| `/cef-background` | Run with below-normal process priority, no UI, and low-impact single-threaded extraction. For uninstall with a writable target, opt into asynchronous temp-child relaunch; the parent returns 109 after the child starts. |
| `/cef-headless` | Disable progress UI without changing extraction behavior. |
| `/cef-parent=<hwnd>` | Pumped parent window for progress notifications and supported asynchronous-uninstall lifecycle results. |

Examples:
```
MyApp.exe /cef-update                    # Check for updates
MyApp.exe /cef-update /cef-forcecheck    # Force update check
MyApp.exe /cef-update /cef-background    # Background update, no UI
MyApp.exe /cef-uninstall                 # Uninstall
MyApp.exe /cef-uninstall /cef-headless   # Silent uninstall
MyApp.exe /cef-uninstall /cef-background # Async; 109 means child started
```

In official builds, `/cef-update`, `/cef-uninstall`, and both
`/cef-retention-*` commands require `enable_explicit_modes: true` in the
bootstrap executable's embedded configuration. This requirement also applies
when a client DLL is present. See
[Standalone Mode Security](#standalone-mode-security) for configuration-source
and build-type behavior.

## Background Update API

Client DLLs can trigger background updates using the `RunInstaller` export:

```cpp
#include <windows.h>
#include "include/wrapper/cef_util_win.h"

// Function pointer type
typedef const char* (*RunInstallerFunc)(const char* command,
                                        const char* config_json);

void ConfirmHealthThenCheckForUpdates() {
  // Get export from bootstrap.exe
  HMODULE bootstrap = GetModuleHandle(nullptr);
  auto run_installer = reinterpret_cast<RunInstallerFunc>(
      GetProcAddress(bootstrap, "RunInstaller"));
  if (!run_installer) {
    return;  // Not running under bootstrap
  }

  // Read config from client DLL resource
  std::string config_json;
  if (!cef_util::ReadResourceData(GetCodeModuleHandle(),
                                  L"CEF_INSTALLER_CONFIG",
                                  &config_json)) {
    return;
  }

  // Copy the result before another call invalidates it on this thread.
  const char* confirmation = run_installer("launch_success", nullptr);
  std::string confirmation_json = confirmation ? confirmation : "";
  // Application helper: require valid JSON with "success" set to true.
  if (!ParseInstallerSuccess(confirmation_json)) {
    return;
  }

  // Skip the update unless launch health was confirmed successfully.
  const char* result = run_installer("update", config_json.c_str());
  // ...
}
```

Applications that use launch-health tracking should confirm the current launch
before checking for an update. Call `launch_success` after CEF reaches a
healthy steady state, such as after the first page renders successfully. The
returned pointer remains valid only until the next `RunInstaller` call on the
same thread, so copy and parse the result immediately. Continue with `update`
only when the result contains `"success": true`. If confirmation is
unavailable, malformed, or unsuccessful, skip the update for this run. This
keeps the current, known-good version eligible as a fallback under the existing
pruning rules.

Cefclient follows this sequence once, 60 seconds after startup. If confirmation
fails, cefclient does not check for an update during that process.

`RunInstaller` does not sequence these calls automatically. Applications that
want a confirmed fallback must call `launch_success` before `update`.
Confirmation does not pin a version indefinitely: the application must remain
registered for the same platform, the version must satisfy that platform's
global `vmin`, and a revoked version can still be removed.

`launch_success` needs no configuration and does not acquire the installer lock
or open the database. The bootstrap creates the version-specific launch-state
record before `RunWinMain`. This is separate from the version-independent
liveness record used to determine when an application registration is stale.
Updating liveness alone does not confirm a launch or protect a particular CEF
version.

### RunInstaller Commands

| Command | Description |
|---------|-------------|
| `"install"` | Install CEF if not present. |
| `"update"` | Check for and install updates. |
| `"uninstall"` | Unregister app and prune unused versions. |
| `"query"` | Query installed versions (no modifications). |
| `"retention_dry_run"` | Return a store-wide retention report without modifying installer state. |
| `"retention_apply"` | Recompute and apply store-wide retention. |
| `"launch_success"` | Confirm launch health — the current CEF version is working. Lightweight (no lock, no database). |

### Extended Configuration

When calling `RunInstaller`, you can include extended configuration fields in
the JSON:

```json
{
  "appid": "A3B9C4D5-E6F7-4A8B-9C0D-E1F2A3B4C5D6",
  "vmin": "151.1",
  "vmax": "",
  "abi_hash": "1234567890ABCDEF",

  "cdn_urls": ["https://cef-builds.spotifycdn.com/"],
  "install_path": "",
  "bundled_cef_path": "",
  "certificate_thumbprint": "",
  "force_check": false,
  "show_progress_ui": true,
  "parent_window": "0",
  "local_download_path": ""
}
```

| Field | Default | Description |
|-------|---------|-------------|
| `cdn_urls` | *(omitted)* | One through three ordered HTTPS base URLs for this operation. When omitted, resolution falls through to the selected application config and then the hardcoded default. See [CDN file format](../../../tools/cefbuilds/README.md). |
| `install_path` | `""` | Exclusive custom CEF installation path. A safe existing read-only directory may be used by query/automatic startup; mutations require write access and never fall back. Empty uses the standard search. |
| `bundled_cef_path` | `""` | Path to pre-extracted bundled CEF directory. Used in-place (not copied to shared install dir). Also accepted in the client DLL's embedded `CEF_INSTALLER_CONFIG` resource (see [Configuration Fields](#2-configuration-fields)). See [Version Selection](#version-selection). |
| `certificate_thumbprint` | CEF certificate | Non-empty expected catalog-signer thumbprint. A trusted caller may select another Windows-valid signing certificate for legitimately re-signed distributions; use a distinct `install_path` and matching client-side load policy. |
| `force_check` | `false` | Force CDN version check even if cache is fresh. |
| `show_progress_ui` | `true` | Show progress dialog (false for silent operation). |
| `parent_window` | `"0"` | HWND as a base-10 unsigned string. A JSON number is accepted only when finite, non-negative, integral, exactly represented, and within `uintptr_t`. |
| `local_download_path` | `""` | Operation-local directory or UNC root with the CDN mirror layout. Normal hash, catalog, signature, metadata, and size validation still applies; this source does not persist revocation deltas. |

`cdn_urls` entries are at most 2048 bytes each. They must have an HTTPS scheme
and non-empty host, cannot contain userinfo, a query, fragment, newline, or
backslash, and are normalized to a trailing-slash path prefix. Supplied order
and duplicates are preserved. An empty array, more than three entries, a
wrong type, or an invalid URL is config error 100.

`RunInstaller` JSON applies only to that API call. Automatic startup resolves
CEF from an embedded configuration before `RunWinMain`; a later API call does
not retroactively change that selection. To rely entirely on `RunInstaller`, do
not embed `CEF_INSTALLER_CONFIG` in either the client DLL or bootstrap `.exe`.
See [Configuration Fields](#2-configuration-fields) for where individual fields
are accepted and [Config Security](#config-security) for application-config
source priority and fallback behavior.

### Result JSON Format

```json
{
  "success": true,
  "outcome": "committed",
  "libcef_path": "C:\\ProgramData\\CEF\\Versions\\151.1.0\\windows64\\Release\\libcef.dll",
  "installed_version": "151.1.0"
}
```

Or on error:
```json
{
  "success": false,
  "outcome": "failed",
  "error_code": 103,
  "error_name": "NO_MATCHING_VERSION",
  "error_message": "No compatible CEF version found"
}
```

`outcome` is always `committed`, `cleanup_deferred`, or `failed`.
`cleanup_deferred` is successful and includes a `warnings` string array naming
physical or auxiliary cleanup left for a later pass. Depending on the command,
this may include trash or quarantine reclamation, retention evidence cleanup,
deferred version removal, or retry-state cleanup. Check `retry_required` to
determine whether the same operation should be run again. Database and
version-index publication are hard commit requirements and therefore return
`failed`, never deferred cleanup. Failed results always contain numeric
`error_code`, symbolic `error_name`, and a diagnostic string. Successful
results omit all error fields. The returned pointer is thread-local and
remains valid until the next call on the same thread or until that thread
exits. Copy the JSON into caller-owned storage before another same-thread call
or before the calling thread exits if it must be retained.

There is intentionally no `RunInstaller("last_error")`: a process-global
query would race concurrent calls and duplicate the synchronous per-call and
startup results.

## How It Works

### Automatic Installation

The bootstrap's startup behavior depends on whether a client DLL is present.

**When a client DLL is present:**

1. Bootstrap loads client DLL with `DONT_RESOLVE_DLL_REFERENCES` (no code
   execution) and verifies its code signature
2. Reads config from client DLL resource (falls back to bootstrap resource only
   when the client resource is missing)
3. If no config found: installer is skipped, app launches normally
4. If `/cef-uninstall`: runs uninstall and exits
5. Resolves CEF — searches for a compatible version in the shared directory,
   downloads from CDN if needed (same logic as standalone auto-install). If
   `/cef-update` was specified, a CDN check is forced.
6. Populates the size-gated `cef_version_info_t` startup result
7. Loads the client DLL and calls `RunWinMain`
8. If CEF resolution failed: `libcef_path` is null and
   `installer_error_code`/`installer_error_message` describe the failure. The
   client tries adjacent fallback; cancellation (108) should exit gracefully
   with "restart to retry," while no fallback is a fatal error.

The appended startup fields require
`CEF_VERSION_INFO_SIZE_WITH_INSTALLER_ERROR`. Clients must check `size`
before reading them. Resolved success has a non-null path and code 0; installer
not configured has a null path, code 0, and null message; recoverable failure
has a null path, nonzero code, and UTF-8 message. All pointers are
bootstrap-owned process-lifetime storage and must not be freed. Crashpad keys
`bs-install-error`, `bs-install-msg`, `bs-install-vmin`, `bs-install-vmax`,
`bs-install-policy-denied`, and `bs-install-cancelled` supplement this
synchronous contract. For example, the installer-specific annotations for error
103 in representative cefclient Crashpad metadata look like this:

```json
{
  "bs-install-error": "103",
  "bs-install-msg": "No CDN version matches requirements (platform = windows64, version >= 151.1, ABI hash = 1671cc913eeb4ecf); no validated CDN manifest candidates were available",
  "bs-install-vmax": "unbounded",
  "bs-install-vmin": "151.1"
}
```

If installer resolution fails and the adjacent `libcef.dll` fallback is also
unavailable, cefclient additionally records a `LOG_FATAL` message. That field
is generated by the client and is not part of the bootstrap annotation contract.

**Standalone mode (no client DLL):**

1. Bootstrap reads config from its own embedded resource.
2. If no config found: installer is skipped, bootstrap fails (no client DLL to
   fall back to)
3. If `/cef-uninstall`: runs uninstall and exits
4. Resolves CEF — searches for a compatible version in the shared directory,
   downloads from CDN if needed. If `/cef-update`, forces a CDN check.
5. On success: exits (there is no client DLL to hand off to)

In official builds, `enable_explicit_modes` gates explicit commands and
standalone auto-install, but not normal startup resolution with a client DLL;
see [Standalone Mode Security](#standalone-mode-security).

### Uninstall execution and outcomes

**Requirement:** In official builds, the `/cef-uninstall` command requires
`enable_explicit_modes: true` in the bootstrap executable's embedded
configuration, whether or not a client DLL is present. See
[Standalone Mode Security](#standalone-mode-security). The
`RunInstaller("uninstall")` API remains available without this flag.

**Normal behavior:** When the executable is outside the selected writable
install directory, `/cef-uninstall` waits for the uninstall to finish. Exit 0
means the application registration and required version-index update were
committed. Some files may still be awaiting safe deletion; in that case the
operation still returns 0 and logs `cleanup_deferred` warnings. Database or
required index failures return the corresponding nonzero error instead.

`RunInstaller("uninstall")` always runs in the current process and reports the
same committed, deferred-cleanup, or failed distinction in JSON. See
[Result JSON Format](#result-json-format) for the general outcome contract.

**When uninstall continues in another process:** The CLI starts a temporary
child and returns 109 only when:

- `/cef-background` requests an asynchronous uninstall; or
- the running executable is inside the selected install directory and must exit
  before self-removal can continue.

Exit 109 means the child started and uninstall is still pending; it does not
mean uninstall completed. A caller that supplies a valid, continuously pumped
`/cef-parent` window receives a `relaunch_started` handoff and a correlated
`operation_result` after the child's result and progress UI are finalized. The
terminal result does not mean the child process has exited. Callers without a
supported window receive no asynchronous completion contract. Do not
automatically rerun `/cef-uninstall` after 109 or missing delivery; a later
invocation is a new operation, not a status query. Use non-background external
uninstall or `RunInstaller("uninstall")` when synchronous completion is
required.

The temporary file set contains the executable, required runtime DLLs,
optional `crash_reporter.cfg`, and validated `cef_uninstall_state.json`. It
also contains the already-authenticated client DLL under its actual basename
only when that DLL's resource supplied the selected application config. A
bootstrap-resource selection copies no client DLL.

**Failures and retries:** Before deciding whether a child is necessary, the
bootstrap safely compares the executable and target directory identities. If it
cannot determine their relationship, or if a required child cannot be prepared
or started, it returns 105 without uninstalling in the current process.

If no writable target is available, uninstall returns configuration error 100
without starting a child. The diagnostic explains whether no valid install
directory was found, the directory is not writable, or the configured path is
not a directory. This includes an exclusive custom or administrator store that
is readable but cannot be modified.

Registrations never expire automatically. After registration removal and the
required index update commit, later writer operations retry deferred `.trash/`
and orphan cleanup.

### Enterprise Policy

Managed deployments can disable the standard shared user store, select an
ordered HTTPS source list or trusted local/UNC mirror, or disable external
downloads completely. Policy is machine-wide, takes precedence over
operation-specific download sources, preserves offline provisioned/bundled
selection, and reports valid enforcement separately from malformed policy.
See [ADMIN_POLICY.md](ADMIN_POLICY.md) for the normative registry schema,
architecture view, provisioning procedures, revocation curation, and
administrator troubleshooting.

### Download Source Precedence and Robustness

For each operation, the installer selects one effective download source and
keeps that selection fixed. A source is a policy decision, local mirror, or
ordered URL list. An origin is one URL within an ordered list.

#### Source selection

| Priority | Source | Behavior |
|----------|--------|----------|
| 1 | Enterprise policy | Policy can select the hardcoded default CDN, an ordered HTTPS list, a local/UNC mirror, or disabled downloads; lower priorities are ignored. |
| 2 | Operation-local mirror | `/cef-download-path` or the equivalent operation setting uses local files without HTTP. |
| 3 | Operation URL list | `cdn_urls` supplied to `RunInstaller` provides one through three ordered HTTPS origins. |
| 4 | Selected application URL list | Uses `cdn_urls` from the application config selected by [normal config precedence](#config-security). |
| 5 | Hardcoded CEF CDN | Used when no higher-priority source is configured. |

Client-resource and bootstrap-resource configs are alternative application
sources. Normal config precedence selects one; their URL lists are never
combined.

#### Origin failover and version fallback

For a URL source, the revocation list and manifest independently try each
origin in order. After selecting a version, the installer keeps that version's
`<archive>.sha256` sidecar and archive on the same configured origin. If the
sidecar is missing, it verifies the archive with the SHA1 from the validated
manifest. Every origin is tried for that version before version fallback is
considered.

The installer selects at most one next-best compatible, non-revoked version
from the same validated manifest when:

- every URL origin reports that the selected archive is missing;
- the effective local or policy mirror lacks the archive; or
- candidate-specific hash, extraction, signature, catalog, or metadata
  verification fails after allowed recovery.

It does not change versions after cancellation, an outage across all origins,
policy denial, or a local write, permission, staging, or publication failure.
Those failures are terminal for the operation.

#### Resuming interrupted HTTP downloads

Only archive downloads are resumable. A partial is reusable only while both
its configured origin and its final origin after redirects still match. A safe
non-empty partial sends `Range: bytes=N-`. The installer appends only after a
valid `206` response whose `Content-Range` begins at N. If the server returns
`200`, the installer safely restarts from zero using that response without an
extra request.

A configured- or final-origin change deletes the old partial before new
response bytes are written. Each version candidate permits at most one
additional full request without `Range`, shared across all origins. That
request may recover from a final-origin change that needs another response,
invalid Range protocol including `416`, a completed-response length
inconsistency, or a hash mismatch.

An interruption, timeout, or truncated transport may retain a matching safe
partial. Moving to another configured origin deletes it first. Cancellation
ends the current operation but may preserve a safe partial for a later attempt.
Local and UNC mirrors always copy from zero and never use HTTP Range.

#### Cache and cleanup

Each complete or partial archive is limited to 500 MB. A complete archive is
published to the cache only after length and SHA256/SHA1 validation. It is
removed after the checked version index and required application registration
have been published successfully.

Extraction, signature, metadata, and publication failures before commit retain
the archive for retry. Failure to delete it after commit reports successful
`cleanup_deferred`. Installer-owned complete archives and structurally valid
origin-bound partials are pruned after seven days; unrelated files are not
matched. There is no aggregate byte or LRU quota.

### Shared Installation Directory

CEF uses a shared directory for installed versions. The installer resolves
directories using a single priority-ordered search that collects **readable**
directories and stops at the first **writable** one.

**Candidate locations** (searched in priority order):
1. `HKLM\SOFTWARE\CEF\InstallLocation` registry value (requires admin to set)
2. `%ProgramFiles%\CEF\`
3. `%LocalAppData%\CEF\`

An `install_path` embedded in the client DLL is an explicit per-application
override; the operation-specific `RunInstaller` field has the same directory
semantics. Either takes precedence over the standard search, and only that
directory is used. An existing safe readable but non-writable directory
remains the sole read-only store. A writable directory is the sole read/write
store. Invalid, unsafe, inaccessible, or missing read-only paths fail without
default-search fallback. Query never creates or write-probes the custom
directory.

`HKLM\SOFTWARE\CEF\InstallLocation` is a machine-wide default candidate, not a
mandatory enterprise-policy location. It participates in the same ordered
search and source-derived role rules as Program Files and LocalAppData.
Mandatory policy values live under `HKLM\SOFTWARE\Policies\CEF`; see
[ADMIN_POLICY.md](ADMIN_POLICY.md).

`install_path` must be distinct from every resolved standard candidate. An
exact, normalized, or safe same-directory alias of the HKLM, Program Files, or
LocalAppData candidate is configuration error 100 and never falls through.
Omit `install_path` when consuming a standard store. On 64-bit Windows the
HKLM provisioning value uses the shared 64-bit registry view for every process
architecture; see [ADMIN_POLICY.md](ADMIN_POLICY.md).

**The algorithm:** For each candidate in priority order, the installer checks
if the directory is readable (add to scan list) and writable (use for
installs). The search **stops at the first writable directory**. This means
readable directories never include locations with lower security priority
than the writable directory.

| Scenario | Readable dirs (in search order) | Writable dir | Notes |
|----------|---------------------------------|--------------|-------|
| **Admin**, no registry | ProgramFiles | ProgramFiles | LocalAppData never checked |
| **Standard user**, ProgramFiles exists | ProgramFiles, LocalAppData | LocalAppData | Sees admin-installed versions |
| **Admin**, HKLM registry set | Registry path | Registry path | Exclusive — naturally falls out |
| **Standard user**, HKLM registry set | Registry, ProgramFiles, LocalAppData | LocalAppData | Reads from all admin locations |
| **Official elevated automatic startup, `enable_explicit_modes: false`, no registry** | ProgramFiles | none | ProgramFiles is read-only; LocalAppData is never checked |
| **Official elevated automatic startup, `enable_explicit_modes: false`, HKLM registry set** | Registry path, ProgramFiles | none | Both locations are read-only; LocalAppData is never checked |
| **Official elevated automatic startup, `enable_explicit_modes: true`, no registry** | ProgramFiles | ProgramFiles | Stops at ProgramFiles |
| **Official elevated automatic startup, `enable_explicit_modes: true`, HKLM registry set** | Registry path | Registry path | Stops at the first writable location |
| **`install_path` writable** | install_path | install_path | Exclusive custom role, regardless of path spelling |
| **`install_path` read-only** | install_path | none | Exclusive selection; unregistered and untracked |

**Security:** Directory roles come from candidate source, never ACLs or path
prefixes. Elevated operations do not search `%LocalAppData%`, which prevents a
privileged process from trusting content in a user-writable directory. In the
official automatic-startup rows, `enable_explicit_modes` is a trusted bootstrap
setting, not enterprise policy or a directory permission. This restriction is
specific to automatic startup: an elevated client may still use
`RunInstaller("install")` or `RunInstaller("update")` to write to the first
writable administrator location when the setting is false. Non-official builds
also allow administrator mutation for development and testing. See
[Background Update API](#background-update-api).

If no writable directory is available but a compatible version already exists
in a readable directory, the installer returns that version instead of failing.
This covers the common case where an admin installed CEF to `%ProgramFiles%`
and a non-elevated app simply needs to use it.

**Directory permissions:** The installer does not set or modify ACLs on the
install directory. It relies on inherited permissions from the parent directory,
which are already correct for the standard locations (`%ProgramFiles%` restricts
write access to administrators; `%LocalAppData%` restricts access to the owning
user). When using `HKLM\...\InstallLocation` or `install_path` to configure a
custom location, the administrator or app-specific installer with admin
permissions is responsible for setting appropriate permissions on that
directory before use. An `install_path` store is application-owned by
contract regardless of path spelling, ACLs, writability, or elevation, and is
eligible for explicit registration retention. Durable administrator
provisioning uses the source-derived HKLM role (which may point anywhere) or
Program Files; those roles are never eligible for user-liveness retention.

Directory structure:
```
CEF/
├── installer.json              # Database of registered apps
├── versions.json               # Version index for lock-free reads
├── revocation_cache.json       # Cached CDN revocation delta
├── cef_installer.log           # Installer log file
├── .cache/                     # Manifests (1-hour TTL); validated/partial archives (7-day TTL)
├── .launch/                    # Per-app launch health sentinels (survive pruning)
├── .staging/                   # Temp extraction (same-volume for atomic rename)
├── .trash/                     # Pending deletions from in-use versions
└── Versions/
    ├── 151.1.0/
    │   └── windows64/          # Platform: windows64, windows32, or windowsarm64
    │       ├── cef_version.json    # Version metadata (from build, signed in catalog)
    │       ├── catalog.cat         # Code signing catalog
    │       ├── CREDITS.html
    │       ├── LICENSE.txt
    │       ├── README.txt
    │       └── Release/            # Binaries and resources
    │           ├── libcef.dll
    │           ├── chrome_elf.dll
    │           ├── chrome_100_percent.pak
    │           ├── resources.pak
    │           ├── icudtl.dat
    │           ├── locales/
    │           └── ...
    └── 151.2.0/
        └── windows64/
            └── ...
```

The platform subdirectory (`windows64`, `windows32`, or `windowsarm64`) allows
different architectures to coexist within the same version directory.

### Version Selection

The installer considers two sources of CEF versions: **installed versions**
from the [selected installer-managed directory](#shared-installation-directory),
and an optional **bundled version** shipped with the application via
`bundled_cef_path`.

`unchecked_cef_path` is resolved before version selection and bypasses this
process entirely; see [Unchecked CEF Path](#unchecked-cef-path).

#### Compatibility Filtering

Both installed and bundled versions must pass these checks:
- Version >= `vmin` and <= `vmax` (if specified)
- Matching `abi_hash` (if specified, required for sandbox)
- Matching platform (e.g., `windows64`)

Installed versions are signature-verified at download time (catalog +
certificate thumbprint). For bundled versions, startup verifies only that
`catalog.cat` exists as a regular non-reparse file. That is a
distribution-layout check: the catalog signature and member hashes are **not**
verified at runtime, because hashing a typical distribution (~236 files, ~370
MB) would add seconds to every app startup. Bundled integrity rests on the app
developer's signed installer/package.

`channel` selects what the installer downloads, not what it runs. It chooses
the stable or beta manifest URL for a network or mirror check, but channel is
not recorded in installed metadata and does not filter installed candidates.
Version range, ABI hash, platform, revocation, and launch-health state define
runtime eligibility; consequently a stable-channel app may use a compatible
version previously installed through a beta-channel request. To avoid adopting
a beta version from a newer milestone in a shared store, follow the
[maximum-version guidance](#maximum-version-guidance) and cap `vmax` at the
approved stable milestone. This limits eligible versions but does not identify
their source: strict stable/beta isolation requires separate `install_path`
stores.

#### Selection Decision Tree

This is the single source of truth for resolution order. The first matching
branch wins; later sections describe the individual mechanisms in more detail.

```text
unchecked_cef_path set and libcef.dll present there?
├─ yes → use it as-is (no version / abi / signature / revocation checks). Done.
└─ no  → continue

Build candidate sets, each filtered by vmin/vmax, abi_hash, and platform:
  • installed: shared-dir versions, EXCLUDING revoked AND crash-disqualified
  • bundled:   the bundled_cef_path version, if configured

A. Primary selection — does a qualifying candidate exist?
   ├─ installed and (non-revoked) bundled both qualify
   │     → newer wins; on a tie the installed version wins (it passed the
   │       installer's download-time catalog verification). Done.
   ├─ exactly one qualifies → use it. Done.
   └─ none qualify          → go to B

B. CDN download (skips installed + crash-disqualified versions)
   ├─ best compatible, non-revoked build installs → Done.
   ├─ candidate-specific absence/content failure
   │     → try one next-best entry from the same manifest; success → Done.
   └─ no match / revoked / terminal failure       → go to C

C. Last-resort fallback (a demoted version beats a broken app)
   ├─ a revoked bundled version exists                → use it. Done.
   ├─ else newest non-revoked crash-disqualified
   │       installed version exists                   → use it. Done.
   └─ else                                            → fail (no version)
```

The mechanisms used by the decision tree are detailed below:
[Bundled Version Behavior](#bundled-version-behavior),
[Revocation](#revocation), [Unchecked CEF Path](#unchecked-cef-path), and
[Launch Health Tracking](#launch-health-tracking) (crash-disqualification).

#### Bundled Version Behavior

When `bundled_cef_path` is specified (via the client DLL's embedded
`CEF_INSTALLER_CONFIG` resource or `RunInstaller` JSON):

- The bundled directory must contain `Release/libcef.dll`, `cef_version.json`,
  and the package's signed `catalog.cat`. Runtime checks only that the catalog
  is present as a regular non-reparse file; signature/member verification is the
  packaging pipeline's responsibility.
- The bundled version is **used in-place** — it is never copied to the shared
  install directory. This is intentional: CDN-installed versions have an
  additional installer-enforced catalog-verification step.
- Bundled distributions use the revocation behavior summarized below. The
  [decision tree](#selection-decision-tree) defines their exact ordering
  relative to installed and downloaded versions.

#### Revocation

The CDN publishes a revocation list (`revoked.json`) of versions with known
security issues. Revoked versions are handled differently depending on source:

| Source | Revocation behavior |
|--------|-------------------|
| **Installed** | Always excluded — never selected on any branch of the [decision tree](#selection-decision-tree), including the last resort. Pruned on next install/update. |
| **CDN** | Blocked from download even if CDN still lists them (caching delay). |
| **Bundled** | Demoted, not excluded — drops out of primary selection but survives to the last resort (branch C). |

#### Query Command

The `query` command uses the same selection logic (installed vs. bundled, newer
wins, installed wins ties) and does not contact the CDN. It reads all readable
directories' valid `versions.json` indexes and does not require a writable
directory. A missing or corrupt index is not replaced by a directory scan on
the query path; query remains index-only and recovery belongs to automatic
startup or the next writer-locked mutation. Revocation is checked using the
compiled-in baseline and any disk-cached CDN delta (no network required).
Revoked bundled versions are demoted, matching install/update behavior. It is a
lightweight, offline-capable operation.

#### Install, Update, and Read-only Behavior

| Operation | Local behavior | Version-manifest check | Possible writes |
|-----------|----------------|------------------------|-----------------|
| **Automatic startup** | Uses the best compatible candidate | Only after a local miss | Install, register, and prune when writable |
| **`install`** | Uses the best compatible candidate | Only after a local miss | Install, register, and prune |
| **`update`** | Keeps the best candidate as a fallback | Always; cached or remote as permitted | Install, register, and prune |
| **`query` and read-only resolution** | Reports the best local candidate | Never | None |

For `update`, a manifest entry that is the same, older, unavailable, or revoked
leaves the local result unchanged and returns a successful no-op. `force_check`
bypasses cache freshness but does not force a download.

**What all operations validate:** Every operation uses the same side-effect-free
offline selector. It receives installed candidates in directory-priority order,
optional bundled metadata, compatibility requirements, effective revocations,
and optional launch-health disqualifications. For duplicate `(version,
platform)` entries, the first valid candidate from the highest-priority
directory wins.

Before selection, each indexed installed candidate is checked against its
per-version metadata, required catalog and `libcef.dll` files, and reparse-safe
canonical path. These checks add filesystem work for each indexed candidate but
do not hash the distribution or reverify its signature. Launch-health
disqualification applies only to installed candidates; the app-shipped bundled
candidate remains eligible as a fallback. Results retain whether the selected
version was installed or bundled and whether it represents a rollback.

**Read-only guarantees:** Query and read-only resolution do not repair indexes,
reconcile state, register applications, prune versions, reclaim trash, or write
caches. Bundled CEF remains eligible when no writable directory exists.

**Startup concurrency:** Automatic startup performs offline selection before
acquiring the writer mutex. When it selects an installed version, it holds a
no-delete handle on `Release/libcef.dll` through `RunWinMain`, preventing a
concurrent prune from moving that version. If removal wins the race, startup
rereads the indexes and selects again.

**Emergency startup recovery:** If normal automatic startup finds no usable
indexed or bundled candidate, it may scan roots whose index is confirmed missing
or corrupt. A valid index—including a valid empty index—remains authoritative
and is never supplemented by scanning. An integrity failure does not delete the
damaged index; an inconclusive I/O failure fails closed without scanning.

The recovery scan examines at most four roots and 128 version directories, with
a soft 500 ms elapsed-time budget because synchronous Windows filesystem calls
cannot be interrupted. Every discovered candidate passes the normal metadata,
distribution, path, platform, ABI, range, revocation, launch-health, and lease
checks. Recovery does not acquire the writer mutex, access the network, modify
state, or repair the index. `query` never uses this recovery path.

Permanent repair occurs the next time a writable `install`, `update`, or
`uninstall` operation acquires the writer mutex—possibly during the same
automatic startup if the emergency scan finds no usable candidate. The writer
rescans and validates the on-disk version directories, then automatically
rebuilds, atomically writes, and rereads `versions.json`. Invalid version
directories are omitted. If the replacement index cannot be written,
atomically published, reread, or validated, the writer operation stops with a
recovery error.

**Revocation refresh:** Effective revocations combine the compiled baseline with
every valid cache in the readable-directory set. A successful additive refresh
is cached only in the selected writable directory. A recent writable-store cache
avoids HTTP only when both its integrity footer and JSON payload validate.

When that cache is stale or invalid and startup has a usable local candidate,
startup makes one synchronous refresh attempt across the effective ordered
`cdn_urls` list. It tries each origin until one returns a valid `revoked.json`
or the shared 5-second wall-clock deadline expires; a slow earlier origin can
therefore consume the budget before a later origin is reached. Each request has
3-second connect/resolve and 2-second receive/response limits. Internally, the
launch-sensitive request uses asynchronous WinHTTP, tries one address per
origin, and cancels at the shared deadline so DNS, connection, headers, and body
do not multiply the budget. If no origin succeeds, startup uses the compiled
baseline plus valid cached revocations and records an integrity-protected,
source-specific 15-minute backoff.

#### Example Scenarios

**CDN builds nightly, app ships on a 2-week cycle:**

| Installed | Bundled | Bundled revoked? | CDN available? | Result |
|-----------|---------|-----------------|----------------|--------|
| v151.1 | v151.2 | No | — | Bundled v151.2 (newer) |
| v151.2 | v151.1 | No | — | Installed v151.2 (newer) |
| v151.2 | v151.2 | No | — | Installed v151.2 (tie → installed wins) |
| v151.1 | v151.2 | Yes | — | Installed v151.1 (revoked bundled demoted) |
| — | v151.2 | No | — | Bundled v151.2 |
| — | v151.2 | Yes | v151.3 ✓ | CDN v151.3 |
| — | v151.2 | Yes | fails | Bundled v151.2 (last resort) |
| — | — | — | v151.3 ✓ | CDN v151.3 |
| — | — | — | fails | Error |

### Unchecked CEF Path

The `unchecked_cef_path` config field provides a fast path for applications that
bundle `libcef.dll` alongside their own binaries and want to skip the installer
entirely.

When set, the installer checks for `libcef.dll` directly in the specified
directory **before** any other resolution (shared directory scan, CDN download,
bundled version comparison). No version range, ABI hash, platform, signature,
or revocation checks are performed — the application is responsible for the
integrity of the DLL at this path.

```json
{
  "appid": "A3B9C4D5-E6F7-4A8B-9C0D-E1F2A3B4C5D6",
  "vmin": "151.1",
  "abi_hash": "1234567890ABCDEF",
  "unchecked_cef_path": "."
}
```

**Caution with `"."`:** This setting places an unchecked `libcef.dll` beside the
client DLL and makes it the intentional first choice, ahead of installer-managed
or bundled versions. That adjacent DLL can be dangerous for a client that does
not strictly control load ordering. The client must explicitly load the exact
`libcef_path` returned by the bootstrap, as the cefclient reference
implementation does, **before calling any CEF function**. Because `libcef.dll`
is delay-loaded, a premature CEF call can implicitly load the adjacent DLL by
name. Without an adjacent DLL, the same bug would normally fail visibly instead
of silently loading an unintended copy. Use `"."` only when this override is
intentional, its directory is controlled, and the client enforces that ordering.

**Key behaviors:**

- **Relative paths** are resolved against the directory containing the client
  DLL that provided the config. `"."` means "libcef.dll is next to the client
  DLL."
- **Client DLL only:** The field is only read from the client DLL's embedded
  `CEF_INSTALLER_CONFIG` resource. It is ignored in the bootstrap `.exe`'s
  resource. A key supplied in `RunInstaller` JSON is ignored and does not
  enable the bootstrap startup fast path.
- **Fallback:** If `libcef.dll` is not found at the specified path, the
  installer falls through to the normal resolution flow (shared directory, CDN
  download).
- **Uninstall:** The field is ignored for `/cef-uninstall` — uninstall always
  proceeds through the normal database and pruning flow.

**Contrast with `bundled_cef_path`:** `bundled_cef_path` (accepted from the
client DLL's embedded `CEF_INSTALLER_CONFIG` resource and `RunInstaller` JSON)
points to a full CEF distribution with `cef_version.json`, `catalog.cat`, and a
`Release/` subdirectory. It participates in version selection (newer wins,
installed wins ties) and revocation demotion. `unchecked_cef_path` is simpler —
it points directly at the directory containing `libcef.dll` with no metadata
requirements and no version comparison.

**Contrast with no `CEF_INSTALLER_CONFIG` resource:** When neither the client
DLL nor bootstrap executable provides an installer config, the bootstrap skips
CEF resolution and validation entirely and reports “installer not configured”
to the client (null path, error 0). The client then decides how to locate CEF;
for example, cefclient falls back to an adjacent `libcef.dll`.
`unchecked_cef_path` is different: it explicitly asks the bootstrap to return a
particular `libcef.dll`, and if that file is absent, the still-configured
installer continues with normal installed, bundled, or CDN resolution.

## Progress Notifications

When `parent_window` is set in the extended config, progress updates are sent
via `WM_COPYDATA`:

```cpp
// COPYDATASTRUCT.dwData = 0x43454649 ('CEFI')
// COPYDATASTRUCT.lpData = UTF-8 JSON string:
{
  "step_name": "downloading",  // Also "checking", "extracting", "verifying", "installing", "committing", "cleaning"
  "step": 4,
  "total_steps": 9,
  "bytes_done": 1048576,
  "bytes_total": 10485760,
  "message": "Downloading..."
}
```

`step` is zero-based, and `total_steps` is the final step index (`cleaning`,
currently 9), not a step count. A notification with `step == total_steps` means
that the operation reached the cleaning phase; it does not indicate success or
guarantee that no later error occurred. Read-only operations and other
early-return paths report only the work they actually perform. The `CEFI`
stream has no terminal notification. Determine synchronous outcomes from the
`RunInstaller` result or process exit; asynchronous uninstall uses the separate
`CEFR` protocol below. This allows client applications to display custom
progress UI instead of the built-in dialog.

### Asynchronous uninstall lifecycle

For a relaunched `/cef-uninstall` with a valid `/cef-parent`, `WM_COPYDATA`
uses `dwData = 0x43454652` (`CEFR`) for two UTF-8 JSON events:

```json
{"protocol_version":1,"event":"relaunch_started","operation_id":"0123456789abcdef0123456789abcdef","child_pid":1234}
{"protocol_version":1,"event":"operation_result","operation_id":"0123456789abcdef0123456789abcdef","command":"uninstall","success":true,"outcome":"committed","exit_code":0}
```

The public operation ID is 32 lowercase hexadecimal characters. It correlates
events but does not authenticate either process. `operation_result` extends the
normal result JSON: success outcomes are `committed` or `cleanup_deferred`;
failures include matching `error_code`, `error_name`, and `error_message`.
Success uses exit code 0. Failure codes are restricted to the named stable
installer errors 100-108, 110-119, and 199. Exit 109 is reserved for the
original process and is never a child terminal; arbitrary integers paired with
`UNKNOWN_ERROR` are malformed. Warnings are optional. Retention-only result
fields are not emitted for uninstall.

Each payload is at most 32 KiB including exactly one trailing NUL. Failure text
is at most 4096 UTF-8 bytes; at most 32 warnings of 1024 bytes each are sent.
`diagnostics_truncated:true` reports any reduction. Dispatch by `dwData` before
parsing JSON, copy the bytes, return promptly, and parse outside the window
procedure. Lifecycle return values—including 2—are ignored and cannot cancel
work. Each send is one attempt bounded by 500 ms with no retry.

Events from separate operations may interleave, and a terminal can arrive
before its handoff. Buffer terminal-first events by operation ID, attribute
them only after the matching handoff, and keep only the first valid correlated
terminal. Bound and expire correlation state because the channel is not
authenticated, prefer evicting orphan terminals, and consume or remove entries
when the caller no longer needs them. An orphan terminal remains indeterminate.
`child_pid` is diagnostic metadata, not a durable process handle or wait
contract.

The terminal is sent after progress UI closure, and no later progress is
emitted, but it reports logical result/UI finalization rather than child exit.
`cleaning` progress is not completion. Delivery timeout/error, parent window
destruction or reuse, UIPI rejection, process initialization failure, invalid
trusted state, crash, forced termination, and power loss can leave completion
indeterminate. A higher-integrity receiver must explicitly allow `WM_COPYDATA`
with `ChangeWindowMessageFilterEx`; the installer does not change its filter.

### Cancellation via Parent Window

The parent window can request cancellation by returning
`kWmCopyDataResultCancel` (2) from its `WM_COPYDATA` handler:

```cpp
// 'CEFI' in little-endian — identifies CEF installer progress messages.
constexpr ULONG_PTR kCefInstallerProgressId = 0x43454649;
// Return this from WM_COPYDATA to request cancellation.
constexpr LRESULT kCefInstallerCancel = 2;

case WM_COPYDATA: {
  COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lParam);
  if (cds->dwData == kCefInstallerProgressId) {
    // Process progress JSON...

    // Return kCefInstallerCancel to cancel the installation.
    if (user_wants_cancel) {
      return kCefInstallerCancel;
    }
  }
  return TRUE;  // Message handled, continue installation
}
```

Only the specific sentinel value (2) triggers cancellation. Standard
`WM_COPYDATA` return values (`TRUE` = handled, `FALSE` = not handled), timeouts,
and send errors are all treated as "continue". This means a well-behaved parent
following MSDN conventions will never accidentally cancel the install.

### Parent Window Handle (Cross-Process Security)

The `parent_window` HWND is treated as untrusted input from an external
process. The following table describes how the installer's progress dialog
interacts with that window:

| Aspect | Progress dialog behavior |
|--------|--------------------------|
| **Ownership** | No owner relationship established (`CreateDialogParamW` receives `NULL`) |
| **Window state** | Never modified (`EnableWindow`, `SetForegroundWindow` not called) |
| **Positioning** | Read-only via `GetWindowRect` for centering the progress dialog |
| **Validation** | `IsWindow()`, `IsWindowVisible()`, `IsIconic()`, `MonitorFromRect()` checks |
| **Dialog lifetime** | Independent of parent; the dialog survives if the parent is destroyed |
| **Z-order** | Always topmost for visibility regardless of parent |

The HWND is only a positioning hint and progress-notification destination. Its
window procedure may request cancellation, but cannot control another process
or window through the installer. During retention apply, cancellation after
the `committing` state begins is deferred until the next safe checkpoint before
physical cleanup. See [Config & Input Parsing](SECURITY.md#5-config--input-parsing)
for the cross-process trust boundary and security invariants.

## Exit Codes

When running in standalone installer mode (`/cef-update`, `/cef-uninstall`,
`/cef-retention-dry-run`, or `/cef-retention-apply`), the process exit code
indicates success, pending work, or failure.

Installer-specific exit codes use the 100-199 range to avoid conflicts with
`cef_resultcode_t` values (Chrome codes: 0-40+, sandbox codes: 7006+).

The authoritative numeric values and their meanings are defined alongside the
constants in [installer_constants.h](installer_constants.h#L160). For enterprise
policy outcomes and remediation, see [ADMIN_POLICY.md](ADMIN_POLICY.md).

## Concurrent Access

Multiple processes can read or use the same CEF store at once. The installer
keeps those reads responsive while allowing only one process at a time to
change a particular writable store. See
[Install, Update, and Read-only Behavior](#install-update-and-read-only-behavior)
for when `query` and automatic startup remain read-only or enter a writer path.

### Protecting a version that is in use

When automatic startup selects an installed version, it keeps
`Release/libcef.dll` open without permission to delete it. Other processes may
use the same version at the same time. If a writer later removes that version,
it first removes the version from `versions.json` so new readers cannot select
it. The writer then tries to move the version directory to `.trash/`. A running
application's open file prevents that move, so physical cleanup is deferred
until after `RunWinMain` returns; the running application is not disrupted.

### Publishing changes safely

A named mutex serializes changes to each writable install directory. Writers
publish durable state in this order:

| Change | Publication order |
|--------|-------------------|
| Add a version | Validate and publish the complete version directory, atomically publish and reread the expanded `versions.json`, then publish the app registration. |
| Remove a version | Publish registration removal when required, atomically publish and reread the reduced `versions.json`, move the directory to `.trash/`, then delete it. Pruning starts with the index update. |

If a durable step fails, the installer stops before starting the next step; it
does not try to roll back work already published. This ordering ensures that
`versions.json` never points to a directory that removal has already moved.
Failure to move or delete files after the required database and index changes
is a successful `cleanup_deferred` outcome, not a failed logical operation. A
running application and a temporary access-denied error are common reasons for
deferred cleanup. See [Result JSON Format](#result-json-format) for how to handle
that outcome.

### Index recovery and existing destinations

Every `versions.json` update is written atomically, reread with the production
parser, and compared with the intended contents. A writer-locked install,
update, or uninstall automatically rebuilds a missing or damaged index as
described in
[Install, Update, and Read-only Behavior](#install-update-and-read-only-behavior).

When the existing index is valid, it remains authoritative. A version directory
that is not listed in the index is treated as an orphan and quarantined rather
than silently added back. Recovery never invents an app registration. Invalid
directory names and version-level reparse points are skipped so they do not
block unrelated changes, but they produce deferred-cleanup warnings. A
persistent artifact keeps later write results at `cleanup_deferred` until it is
removed.

Once an install has downloaded, extracted, and catalog-verified a staging
distribution, any safe regular-file or directory target already present at the
canonical destination is moved opaquely to the reparse-safe `.trash/` directory.
The installer does not read or classify the existing target's contents. It then
renames the current operation's verified staging directory into place before
publishing the expanded index, so existing bytes never win this collision.

A quarantine failure is a hard error that preserves both the target and verified
source at their original paths. A replacement-rename failure is also hard: the
old target remains under `.trash/`, verified staging remains at its source, and
the canonical destination is absent. The old target is never rolled back.
Physical reclamation of a successfully quarantined target is best-effort; if
logical directory and index publication otherwise complete, remaining trash is
reported as `cleanup_deferred` and retried by a later writer.

Staging is owned by the current controller operation and is cleaned up
best-effort on return. It is never persisted as trusted state. A later retry may
reuse verified archive-cache bytes, but it re-extracts the archive and repeats
catalog verification before attempting publication again.

### Lock waits and failure behavior

- The mutex name is derived from the writable install directory, so independent
  stores do not block one another.
- Explicit write commands wait up to 30 seconds by default. If the current
  writer does not finish in time, the waiting command returns
  `kExitCodeLockTimeout`.
- Automatic startup waits at most five seconds when it needs the writer lock.
  On timeout, it returns `kExitCodeLockTimeout` (107). A client DLL receives the
  code and diagnostic through `cef_version_info_t`; standalone mode exits 107.
  If enabled, the progress UI shows localizable “busy” guidance and the error
  code instead of the diagnostic.
- A local-hit startup refreshes its app registration only when the entry is
  missing or changed. It makes a zero-timeout lock attempt and skips the refresh
  if another writer is busy, so application launch is not delayed.
- If a writer exits while holding the mutex, Windows gives ownership to one
  waiter. That process records the abandoned lock and reconciles installer
  state before continuing.
- A version required by an app registered in the same install directory is
  never deleted.

## Version Pruning

Unused CEF versions are automatically cleaned up in the writable directory:
- Each app's required CEF version range is registered by the installer in
  `installer.json`
- Apps are registered by `(uuid, platform)` - the same app on different
  architectures are separate entries
- On uninstall, the app is unregistered and its now-unused version directories
  are pruned immediately. Valid crash-history records for that app remain for
  up to 90 days so a reinstall does not immediately retry known-bad builds.
- Versions not required by any app registered in that install directory are
  deleted
- Revoked installed versions are prunable even when a registration or confirmed
  fallback would otherwise protect them; a usable non-revoked fallback is
  retained when available
- Pruning covers every platform subdirectory; see
  [Pruning Protection](#pruning-protection) for the cross-platform rules
- Pruning happens during uninstall, after a successful install or update, and
  after eligible clean client exits as described in
  [Post-Exit Pruning](#post-exit-pruning)

## Explicit Registration Retention

Registration expiry is disabled by default. Normal commands never remove a
registration because it is old. This includes automatic startup, install,
update, uninstall, query, post-exit pruning, and ordinary `prune`.

Retention runs only when explicitly requested through one of these commands:

- CLI: `/cef-retention-dry-run` or `/cef-retention-apply`
- API: `RunInstaller("retention_dry_run", ...)` or
  `RunInstaller("retention_apply", ...)`

### Recommended workflow

An application-owned maintenance UI or trusted updater should:

1. Run `retention_dry_run`.
2. Show the affected registrations and versions.
3. Warn that removed registrations may require a future download and may break
   offline or download-restricted applications.
4. Run `retention_apply` only after the user or operator confirms.
5. Retry when `retry_required` is true. Treat `cleanup_deferred` as a successful
   logical change with physical cleanup still outstanding.

The CLI is intended for trusted support tools and managed scripts running as
the affected user. The bootstrap must enable explicit commands through its
embedded `enable_explicit_modes` setting.

Do not run retention automatically at startup, after exit, from a system-wide
elevated task, or in response to disk pressure. Those uses require a separate
policy because they have different availability risks.

### Eligible stores

Retention is based on store ownership, not on whether the current process is
elevated or can write to a path.

| Store | Retention allowed? |
|---|---|
| Per-user default store | Yes |
| Application-owned `install_path` store | Yes |
| HKLM-configured store | No |
| Program Files provisioning store | No |

Provisioning stores are rejected before write probing, file logging, or lock
acquisition. The same rules apply to the API and CLI.

### Age and launch evidence

The default age threshold is 180 days. A request may override it with
`max_age_days` in API JSON or `/cef-max-age-days` on the CLI. The accepted range
is 90 through 3650 days, inclusive. Evidence is stale when its age is equal to
or greater than the threshold.

Evidence is evaluated separately for each `(appid, platform)`. The newest
canonical, integrity-valid timestamp wins: either a health sentinel's
`pid_start_time` or a version-less liveness record's `last_launch`.

| Evidence | Result |
|---|---|
| Valid; age is below the threshold | Registration is retained |
| Valid; age meets or exceeds the threshold | Registration is a removal candidate |
| Missing or zero | Age is unknown; registration is retained |
| Malformed, integrity-failed, mismatched, or noncanonical | Age is unknown; registration is retained |
| Future-dated | Age is unknown; registration is retained |

Unknown evidence always protects the registration.

### How retention runs

1. **Preview the current plan with dry-run.** Dry-run takes the writer lock and
   is a read-only operation that produces a report without changing installer
   state. Each evidence file is read atomically, but the reads do not form one
   simultaneous global snapshot.

2. **Recompute and validate the plan during apply.** Apply takes the writer lock
   independently and does not use the earlier dry-run report as input. It first
   loads any interrupted cleanup recorded in installer-owned
   `retention_pending.json` into its working state, then builds a preliminary
   plan. After a progress checkpoint, it reads the launch evidence again and
   builds the final plan.

   The writer lock prevents concurrent installer mutations, but application
   launches can update launch-success or liveness evidence without taking that
   lock, including while the progress callback is running. Apply compares the
   preliminary and final registration-removal and expected version-removal
   sets. If either changed, it makes no changes and returns
   `kExitCodeRetentionSnapshotChanged`, `retry_required:true`, and the updated
   report for review.

3. **Order overlapping launches and enter the commit phase.** There is no
   single instant at which every evidence file is observed. A launch published
   before the direct final read of its canonical liveness file can protect that
   registration. A launch published afterward is ordered after this retention
   operation, even if other evidence files are still being scanned. Legacy
   health files are ordered by their own verified reads. Apply then offers one
   final cancellation checkpoint. Once accepted, the progress state changes to
   `committing`, and database and index publication are non-cancellable. Apply
   does not repeatedly replan or roll back a published database because newer
   evidence appeared after its final read.

4. **Publish the logical changes.** Before changing the database, apply records
   the exact version-cleanup scope in `retention_pending.json`. It saves all
   registration removals in one checked database update, then publishes the
   reduced version index before moving any version directories. If the database
   update fails, the index, versions, and evidence remain unchanged, and apply
   attempts to restore the previous pending scope. If that restore fails, the
   result requires a retry and includes a warning. If index publication fails
   after the database update, the result reports `success:false`,
   `outcome:"failed"`, `registrations_committed:true`,
   `versions_pruned:false`, and `retry_required:true`.

5. **Finish physical cleanup, or preserve it for retry.** Retention removes only
   versions made newly unreferenced by the registration removals. Pre-existing
   unreferenced indexed versions and unrelated revoked versions appear in the
   report but are not removed. Ordinary pruning may remove them during
   uninstall, after a qualifying install or update, or after an eligible clean
   client exit; see [Version Pruning](#version-pruning).

   Evidence is deleted only after logical publication. Apply verifies the exact
   payload, integrity status, and handle-resolved `.launch` parent against its
   final observation, using the same opened file for the checks and deletion.
   New or replaced evidence is preserved, as is any target reached by
   redirecting an intermediate directory through a junction or symlink.

   Live leases, failed directory moves, deferred cancellation, or evidence
   deletion failures may return successful `cleanup_deferred` with warnings. A
   cancellation request made during `committing` is remembered, disables the
   Cancel button, and stops physical cleanup at the next safe checkpoint after
   logical publication. `retention_pending.json` lets a later apply finish the
   exact remaining scope even if the registrations are gone or the index has
   already been reduced. The retry scans on-disk metadata for pending versions
   missing from the index and clears the pending record after cleanup succeeds.

6. **Return a deterministic report.** Reports sort registrations by
   appid/platform and versions by version/platform. Each registration includes
   its full appid, range, ABI, evidence kind, timestamp, age, decision, and
   reason. Each version includes its requirement state before and after
   retention, its compatibility or protection reason, and whether removal is
   expected.

   `reason` is a stable symbolic value suitable for use as a localization key.
   Registration reasons are `provisioning_store_ineligible`,
   `database_pruning_blocked`, `invalid_retention_options`, `invalid_evidence`,
   `missing_evidence`, `future_evidence`, `stale_evidence`, and
   `fresh_evidence`. Version reasons are `revoked`,
   `required_by_remaining_registration`, `confirmed_launch_protection`,
   `newly_unreferenced`, and `already_unreferenced`.

   Optional `diagnostic` text is for troubleshooting only; do not use it for
   localization or program logic. Headless CLI and API calls return JSON.
   Normal CLI use returns deterministic text. For retention, `RunInstaller`
   accepts only `install_path`, `max_age_days`, and `log_level`. Its result
   pointer remains valid until the next call on the same thread or until that
   thread exits.

### Availability warning

Retention trades application availability for recovered disk space. It is not
proof that an application was uninstalled. Applying it may force a dormant
application to download CEF again, and may permanently break an application
that is offline or prohibited from downloading. Use dry-run first.

## Launch Health Tracking

Launch-health tracking is an optional local safeguard against a CEF version
that repeatedly fails during application startup. For opted-in apps, it records
per-version launch outcomes in sentinel files and, after repeated failures,
removes the failing version from normal selection so a later launch can choose
a compatible fallback. Confirmed versions are also protected from pruning.
This per-device recovery mechanism complements, but does not replace,
fleet-wide revocation of a known-bad build.

Launch-health rollback is opt-in per app. The `launch_health` field accepts:

- `"off"` (default): no health-state read for selection, no health sentinel, and
  no local crash rollback.
- `"explicit"` (recommended): only `RunInstaller("launch_success")` confirms.
  Every ordinary `RunWinMain` return is neutral; only a dead process without
  confirmation increments the failure count.
- `"exit_code"`: exit 0 confirms, neutral exit codes preserve history, other
  exits or process death count as failure, and `launch_success` may confirm
  early.

Opt in only when the app is effectively single-instance for a user-data
directory. Apps with conventional exit codes can use `exit_code`; apps with
custom nonzero codes should confirm reliably and use `explicit`. Partial
explicit adoption is unsafe: unconfirmed ordinary exits never reset earlier
failures, so failures can accumulate across otherwise healthy runs.

The default is off because local crash attribution is heuristic; fleet-wide
bad builds belong on the revocation list. With tracking off, a startup-crashing
installed version can remain selected indefinitely. Recovery must come from a
launch-time revocation, another app installing a newer compatible version, or
an app update that raises `vmin` or ships a newer bundle. An in-app
`RunInstaller("update")` cannot help when startup never reaches that call.
Opted-in apps should keep their own confirmed fallback and assume deeper
rollback may require a CDN download or bundled fallback.

For opted-in apps, health evaluation runs during every install or update
check, including a background `RunInstaller("update")` call, so background
updates also keep versions disqualified by repeated launch failures out of
normal selection.

When automatic startup resolves exclusively from a read-only store and no
writable installer state root exists, launch-health tracking is omitted for
that launch.

An app's `launch_health` value controls health tracking and version selection
for that app; it does not hide `.launch/` files belonging to other registered
apps in the same store. Shared maintenance still honors those files regardless
of the current app's mode: confirmed health sentinels can protect versions from
pruning, and retention evaluates each registration's health or liveness
evidence independently. See [Pruning Protection](#pruning-protection) and
[Explicit Registration Retention](#explicit-registration-retention).

### Launch-state files

The `.launch/` directory contains two file formats because it supports two
independent policies:

- A **versioned health sentinel** records whether a particular CEF version
  started successfully. Opted-in launch-health rollback uses it to disqualify
  repeatedly failing versions and protect confirmed versions from pruning.
- A **versionless liveness record** records when the app last launched.
  [Registration retention](#explicit-registration-retention) uses it to decide
  whether a registration may be stale, even when launch-health rollback is
  off.

Keeping them separate lets liveness be published and refreshed independently
of launch-health mode, while preserving crash and confirmation history for each
CEF version across app launches and version changes.

**Versioned health sentinel.** This per-app, per-version state file is written
to the `.launch/` directory under the install directory immediately before
`RunWinMain`:

```
<install_dir>/.launch/<appid_hash>_<version>_<platform>
```

`appid_hash` is the first 16 hex chars of SHA-1(appid). The version and
platform are embedded in both the filename and the JSON body. The file uses
a CRC32 integrity footer (same format as other installer files):

```json
{
  "appid": "A3B9C4D5-E6F7-4A8B-9C0D-E1F2A3B4C5D6",
  "version": "151.1.0",
  "platform": "windows64",
  "pid": 12345,
  "pid_start_time": "133612345678901234",
  "consecutive_failures": 2,
  "running": true,
  "confirmed": false,
  "last_update": "133612345678901999"
}
```

The `pid` and `pid_start_time` fields prevent stale updates. After
`RunWinMain`, the bootstrap updates the launch state only if the PID in the
file still matches the current process. If a newer instance has already
overwritten the file, the exiting process skips the update.
`last_update` is a required, nonzero decimal Windows-epoch FILETIME used only
for launch-history garbage collection. The common writer replaces any caller
value with current time immediately before every pre-launch, explicit
launch-success, normal-exit, or neutral-exit publication. Failure to obtain a
nonzero time fails that publication without replacing prior state. A clean
exit after explicit launch success remains a no-op and does not publish twice.

Because files live in a single `.launch/` directory (not inside version
directories), crash history survives version pruning. This prevents a doom
loop where a crashed version is pruned, re-downloaded from the CDN, and
crashes again.

Writes use a same-directory temporary file and atomic replacement. If the
pre-launch write fails, the error is logged and the client launches untracked
for that run. CRC detects corruption but is not authentication. Both launch
record formats require a valid integrity footer; footerless files and health
sentinels missing `last_update` are invalid old-schema state. Read-only paths
ignore and preserve invalid records, while a writer-locked repair pass may
remove them.

**Versionless liveness record.** All non-bundled main-process launches write
this retention-liveness record immediately before the health sentinel (when
enabled) and before `RunWinMain`:

```
<install_dir>/.launch/<appid_hash>_<platform>
```

Its bounded, integrity-protected body contains only `appid`, `platform`, and a
decimal Windows-epoch `last_launch` timestamp. The version-less two-segment
filename cannot be parsed as a health sentinel or protect/disqualify a version.
Liveness publication and health-sentinel publication have independent success
semantics; liveness success never substitutes for a failed health sentinel.
The bootstrap rewrites it when missing, malformed, identity-mismatched,
future-dated, or at least 30 days old; the content timestamp, not mtime, is
authoritative. This records liveness for later retention policy without
deleting registrations based on age.

### Mode Classification

This applies only to the opt-in modes (`explicit` and `exit_code`).

After `RunWinMain` returns, the bootstrap classifies the exit code:

| Event | Mode | Effect |
|----------|--------|--------|
| **Explicit confirmation** (`RunInstaller("launch_success")`) | Both opted-in modes | Write `running=false`, `confirmed=true`, `failures=0`. |
| **Ordinary return** | `explicit` | Write `running=false`, `confirmed=false`; preserve failures regardless of exit code. |
| **Exit 0** | `exit_code` | Confirm and reset failures. |
| **Neutral exit** (for example 21, profile in use) | `exit_code` | Write unconfirmed and preserve failures. |
| **Other exit** | `exit_code` | Leave `running=true`; count it on the next launch. |

Clients using either opted-in mode can call
`RunInstaller("launch_success", nullptr)` during `RunWinMain`; no config is
needed because the bootstrap records the active sentinel before calling the
client. In `explicit` mode this call is the only way to confirm health. In
`exit_code` mode it can confirm health before process exit. Either way, an
app-level crash after confirmation does not penalize the CEF version, while a
crash before confirmation still can. See the mode table above for behavior when
the call is omitted and [RunInstaller Commands](#runinstaller-commands) for the
API contract.

### Rollback Behavior

This applies only to the opt-in modes (`explicit` and `exit_code`).

On each launch, the installer scans `.launch/` for the app's files, covering
both installed and previously-pruned versions, to build the
**crash-disqualified** set:

1. If a sentinel shows `running=true` and the process is dead, the version is
   treated as having crashed one more time. A `pid_start_time` before the
   estimated current Windows boot boundary is indeterminate and never counts as
   a crash. If boot evidence is unavailable or inconsistent, classification also
   fails open to indeterminate.
2. If three or more consecutive crashes are projected, the version is
   **crash-disqualified**.

Disqualified versions then feed into the
[Selection Decision Tree](#selection-decision-tree): they are removed from
primary selection (so the next-best version is chosen instead) and from the CDN
skip list, but a non-revoked disqualified version remains available as a last
resort if nothing else qualifies. See the decision tree for the exact ordering
relative to revoked and bundled versions.

### Cleanup Strategy

This applies only to the opt-in modes (`explicit` and `exit_code`). Shared
cleanup performed by pruning is described separately in
[Stale File GC](#stale-file-gc).

On successful exit (version confirmed), the bootstrap deletes the `.launch/`
*files* for older versions that were previously confirmed (qualifying those
versions for pruning). It only deletes confirmed-state files; `.launch/` files
recording crash history (`running=true`, or `failures>0`) are kept.
This confirmed-file cleanup is separate from the 90-day age grace applied to
orphaned and below-`vmin` crash history.

This is about the small `.launch/` sentinel files, not the version directories.
A crashed version directory is **not** protected from pruning — only *confirmed*
versions are (see [Pruning Protection](#pruning-protection)) — so a known-bad
version's bits can be reclaimed. Its crash-history file lives separately in
`.launch/` and survives that pruning, which is what keeps the version
disqualified and off the CDN re-download list, preventing a crash-loop.

Cleanup only affects the current app's files. If apps A and B both have
confirmed files for v1, app A confirming v2 deletes app A's v1 file but
leaves app B's v1 file intact.

### Stale File GC

During ordinary pruning, valid orphaned records (no app registered for their
`(appid, platform)`) and records below the minimum `vmin` of all registered
apps on their platform become eligible for age cleanup. They are retained
while their integrity-verified content timestamp is less than 90 days old and
deleted when its age is 90 days or more. Health records use `last_update`;
liveness records use `last_launch`. Filesystem timestamps are ignored.
Consequently, a record that is already old may be deleted the first time it
becomes eligible. A future timestamp or unavailable clock preserves the file.

Writer-locked prune also repairs a reparse point at `.launch/`, removes
final-component reparse launch files without following their targets, and
deletes schema-invalid or noncanonical files, including abandoned atomic-write
temporaries. Query and launch-health evaluation remain read-only and fail
closed on those paths. Turning launch health off for the mutating app removes
its launch records without the age grace. Explicit registration-retention apply
uses its separate retention policy and does not run ordinary launch-record age
GC.

### Pruning Protection

Versions with a confirmed launch state (`running=false`, `confirmed=true`,
`failures=0`) in `.launch/` are protected from pruning. The check spans all
apps — if *any* app has a confirmed file for a version, that version is kept.
This ensures a shared version is not deleted while any app registered in the
same install directory considers it good. Registrations and protection are
intentionally not aggregated across stores.

Protection applies only to a registered app's record at or above that
platform's global `vmin`. An orphaned or below-`vmin` record never protects
version binaries, even while its recent history is retained, its timestamp is
future-dated, or the clock is unavailable. Conversely, an active registered
confirmed record at or above `vmin` protects its version regardless of record
age.

Protection is independent of the pruning app's mode: an `off` app does not
ignore another registered app's confirmed rollback target. Revocation remains
authoritative, so a revoked version is prunable despite confirmation.

**Cross-platform:** Pruning, and therefore launch-state handling, is not gated
to the running installer's platform. Version pruning scans all platform
subdirectories (a 64-bit installer can prune orphaned 32-bit versions and vice
versa), so protection, orphan deletion, and stale GC are evaluated for every
platform's `.launch/` files — each against its own `(appid, platform)`
registration and that platform's `vmin`. Without this, a prune on one platform
could delete a version another platform's launch health is keeping as a
rollback target. The shared `installer.json` database provides registration
context for all platforms.

When a newer version is confirmed, the older version's launch file is
cleaned up as described in [Cleanup Strategy](#cleanup-strategy). Once all
apps have moved on, the version loses its protection and becomes eligible for
pruning.

### Post-Exit Pruning

After `RunWinMain` returns with a **clean exit (code 0)** and the launch state
is updated, the bootstrap runs a prune pass with a minimal lock timeout (1 ms)
so it never blocks exit. This cleans up versions that are no longer needed. If
the lock is unavailable (another writer is running), pruning is skipped
silently.

Before regular pruning, the post-exit pass also checks for version directories
that are missing from a valid version index. It considers only directories with
the expected `Versions/<version>/<platform>` path and moves eligible directories
to `.trash`.

This additional cleanup is skipped when the version index is missing, corrupt,
or unreadable. Regular pruning still handles those cases as before: it may scan
`Versions/`, write a replacement index, and remove versions that are no longer
needed.

Windows may allow a directory containing a loaded DLL to be moved to `.trash`
but prevent its immediate deletion. A later install, update, or uninstall
can remove it after the DLL is no longer in use. Version discovery and index
recovery ignore `.trash`, so a quarantined directory cannot be selected as an
installed version.

Pruning runs **only** on exit code 0 — not on neutral exit codes or failures.
Deleting older confirmed launch files requires both exit code 0 and confirmed
health for the current version. In `explicit` mode, an ordinary exit code 0
does not satisfy that second requirement. A neutral exit such as "profile in
use" implies another instance is concurrently running with `libcef.dll`
loaded (or that an immediate relaunch is coming), which violates the "no
in-use file conflicts" premise that makes post-exit pruning safe. The next
clean exit, or a standalone `/cef-update`, prunes instead.

When `RunInstaller("launch_success")` has already confirmed this launch, the
post-exit handler skips the sentinel write (the confirmation is already
durable). Cleanup and pruning still run, but — as above — only on exit code 0.

## Security

See [SECURITY.md](SECURITY.md) for the full security model, trust boundaries,
invariants, and developer checklists.

### Code Signing

Downloaded CEF distributions require a Windows-valid signed catalog and a
non-empty expected certificate thumbprint before publication. Applications
using a legitimate alternative signer must also use an isolated `install_path`
and a matching client-side load policy. See
[Signature Verification](SECURITY.md#1-signature-verification) for the
authoritative trust model and invariants.

See [Create a signed catalog](../../../docs/code_signing.md#create-a-signed-catalog)
for distribution catalog generation, signing, and verification commands.

### Config Security

Config is loaded with the following priority:

**When client DLL is present:**
1. Client DLL embedded resource
2. Bootstrap `.exe` embedded resource (fallback)

**Standalone mode (no client DLL):**
1. Bootstrap `.exe` embedded resource. This is also the **only** source for
   `enable_explicit_modes`.

The selected source's `cdn_urls` replaces, rather than merges with, every
fallback application-config source.

An embedded resource is trusted and authoritative when present: malformed
JSON, missing/invalid fields, or an empty post-clamp range is a hard config
error and never falls through to another embedded source. Only an absent client
resource may fall back to the bootstrap resource. A missing standalone
resource reports no config; malformed JSON or invalid fields produce config
error 100.

### Enterprise Provisioning

Admin/shared stores use explicitly managed, durable provisioning pins. Use a
dedicated installer bootstrap rather than elevating the application. See
[Provisioning and revocation curation](ADMIN_POLICY.md#provisioning-and-revocation-curation)
for exact-version pins, signer requirements, store isolation, scheduled
updates, and offline mirrors.

### Standalone Mode Security

The `enable_explicit_modes` flag (default `false`) controls whether a
bootstrap binary can be used as a standalone installer. This flag is **only
read from the bootstrap `.exe`'s own `CEF_INSTALLER_CONFIG` embedded
resource** — it is ignored in client DLL resources and `RunInstaller` JSON.
When `false` in official builds:

1. **Explicit commands blocked:** `/cef-update` and `/cef-uninstall` are
   rejected (both standalone and with a client DLL present).
2. **Standalone auto-install blocked:** Auto-install (no client DLL, no explicit
   command) is blocked.
3. **Automatic admin-store mutation blocked:** A launcher with a client DLL may
   read provisioned HKLM/ProgramFiles versions or use bundled CEF, but it does
   not create, probe, register, reconcile, prune, cache, or download into an
   admin-default store and an elevated process does not continue to
   `%LocalAppData%`.

Without `enable_explicit_modes`, the binary can only function as a launcher
when a client DLL is present. CEF resolution still requires a
`CEF_INSTALLER_CONFIG` resource in the client DLL or bootstrap `.exe` —
without one, the bootstrap loads the client DLL with no installer
involvement. The [`RunInstaller`](#background-update-api) export is always
available regardless of this flag. In non-official builds, all standalone
operations are allowed regardless of this flag (for development/testing).

| Bootstrap resource | Explicit commands | Standalone auto-install |
|--------------------|-------------------|-------------------------|
| `enable_explicit_modes: true` | Allowed | Allowed |
| No flag or `false` | **Blocked** | **Blocked** |
| Missing or invalid | **Blocked** | **Blocked** |

App builders who want standalone installer features must explicitly opt in
by embedding `"enable_explicit_modes": true` in the bootstrap `.exe`'s
`CEF_INSTALLER_CONFIG` resource. See
[Config & Input Parsing](SECURITY.md#5-config--input-parsing) for the security
rationale and official-build invariants behind this gate.

### Sandbox Compatibility

The `abi_hash` field ensures sandbox compatibility between client and CEF:
- Hash is computed from sandbox-related struct definitions
- Mismatched hashes prevent sandbox escape or crashes
- Use `CEF_SANDBOX_COMPAT_HASH` from `cef_version.h`

## Build Integration

The installer consumes two embedded Windows `RT_RCDATA` resources. Its
first-run UI can additionally be branded and localized with executable string-
table resources.

### Standard binary distribution CMake example

The standard Windows binary distribution documents an opt-in
`-DUSE_INSTALLER=On` CMake example in its `README.txt`. That Release-only,
bootstrap/sandbox build focuses on cefclient and embeds a generated managed
`CEF_INSTALLER_CONFIG` in the client DLL while staging only the bootstrap,
client DLL, and `chrome_elf.dll` runtime payload. It does not modify bootstrap
resources or enable bootstrap-only explicit command-line or standalone modes.
Replace the sample application identity and follow the signing and compatible
CEF distribution requirements in this document before production use.

### 1. `CEF_INSTALLER_CONFIG` (client DLL or bootstrap resource)

A JSON configuration specifying the application's CEF version requirements.
See [Config Security](#config-security) for loading priority and
[Standalone Mode Security](#standalone-mode-security) for the
`enable_explicit_modes` field. The default bootstrap binary does **not**
include this resource; apps that want bootstrap-driven CEF resolution must
embed the config in their client DLL or add it to the bootstrap `.exe` (at
build time via the `.rc` file, or post-build using a resource editor such
as ResourceHacker).

For build-time integration, add the corresponding `RCDATA` declaration to the
client DLL or renamed bootstrap executable's `.rc` file. To add or update the
resource after building, see
[Embedding Resources with ResourceHacker](TESTING.md#embedding-resources-with-resourcehacker).

### 2. Progress-dialog branding and localization

Applications ship a renamed bootstrap executable and may customize its icon,
version information, and installer strings alongside the embedded config.
See [installer_resources.rc](installer_resources.rc#L23) for the authoritative
dialog layout, string-table IDs, and default English text. The progress UI
loads these resources from the running executable, using the compiled English
text only when a lookup fails.

Override the values in the renamed executable's `.rc` file or with the same
resource editor used to embed `CEF_INSTALLER_CONFIG`. For localization, add
language-specific `STRINGTABLE` blocks with the same numeric IDs; `LoadStringW`
selects the resource for the thread UI language. The error dialog's standard
OK button is supplied and localized by Windows. Translate both
`IDS_INSTALLER_ERROR_MESSAGE_FORMAT` and the body resources so the error-code
label, punctuation, placeholder order, and guidance are all localized. In that
format, `$1` is the localized guidance body and `$2` is the invariant decimal
error code. Both placeholders are required; an invalid customized format falls
back to the complete English format so it cannot omit the numeric error code.

Installer `error_message` values in result JSON and startup reporting remain
unlocalized diagnostics for logs and support. The progress dialog instead
selects localized guidance from `error_code` and includes that numeric code for
correlation.

### 3. `CEF_REVOCATION_LIST` (bootstrap resource)

A compiled-in baseline revocation list embedded in the bootstrap binary.
Generated at build time by `tools/make_revocation_resource.py` from
`tools/cefbuilds/revoked.json` and `cef_api_versions.json`. This ensures the
installer can enforce revocation checks even without network access.

See the `installer_revocation_resource` target in `cef/BUILD.gn`.

## Testing

See [TESTING.md](TESTING.md) for unit, integration, E2E, manual, fuzz, and code
coverage workflows.

## Troubleshooting

### Installer is skipped
- Verify `CEF_INSTALLER_CONFIG` resource exists in client DLL
- Use Resource Hacker or similar to inspect the DLL

### Version not found
- Check `vmin`/`vmax` range matches available versions
- Verify `abi_hash` matches if sandbox is enabled
- Note that `vmin` is clamped to the bootstrap's API version (check logs for
  "clamped" messages)

### Resource loading fails
- Verify the `Release/` directory (alongside `libcef.dll`) contains `.pak` files
  and `locales/` subdirectory
- CEF automatically loads resources relative to `libcef.dll` location

### Reset launch-health history

When [launch-health tracking](#launch-health-tracking) is enabled, the bootstrap
records whether each CEF version reached a healthy state or repeatedly failed
to launch. It uses this history to avoid a crash-disqualified version and to
preserve a confirmed fallback. Reset the history only when those records no
longer reflect the application's actual health.

There is no timed disqualification expiry. Close the application and delete
its files under `<install_dir>\.launch\` to reset local health history.
Task termination, OOM/process kills, logoff, or failure to confirm before
those events can still look like a crash. Newer versions, a rising `vmin`, a
clean last-resort redemption, or this manual reset provide recovery.

### Logs
- Check `<install_dir>\cef_installer.log` for detailed logs (e.g.,
  `%ProgramFiles%\CEF\cef_installer.log` or
  `%LocalAppData%\CEF\cef_installer.log`)
- If no writable install directory is found (including when `install_path`
  points to a read-only directory), logs fall back to `%TEMP%\cef_installer.log`

---

### Overview (`tools/clang/standalone/README.md`)

# C++ Rewriter Tool

A clang-based AST rewriter for C++20 modernization. This tool performs
type-aware code transformations that cannot be done with simple regex,
such as replacing `map.find(x) != map.end()` with `map.contains(x)`.

## Distribution Contents

This is a self-contained distribution that includes everything needed to run:

```
cpp_rewriter/
├── bin/
│   └── cpp_rewriter           # The clang-based rewriter tool
├── lib/
│   └── clang/<version>/       # Bundled clang headers (stdarg.h, etc.)
│       └── include/
├── scripts/
│   ├── run_rewriter.py        # Main wrapper script
│   ├── apply_edits.py         # Applies generated edits to files
│   └── process_edits.py       # Deduplicates and formats edits
└── README.md
```

The bundled `lib/clang/` headers are automatically detected and used by the
wrapper script, so the tool works without requiring a matching system clang.

## Prerequisites

- A C++ project with a `compile_commands.json` file
- Python 3.6+

## Generating compile_commands.json

The tool requires a compilation database to understand your project's
build configuration. Here's how to generate one for common build systems:

### CMake

**Important:** `CMAKE_EXPORT_COMPILE_COMMANDS` only works with **Makefile**
and **Ninja** generators. It does NOT work with Xcode or Visual Studio generators.

```bash
# Using Ninja (recommended)
cmake -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -B build

# Using Unix Makefiles
cmake -G "Unix Makefiles" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -B build

# compile_commands.json is now in build/
```

If you normally use Xcode/Visual Studio, create a separate build directory
just for tooling:

```bash
# Keep your Xcode build, add a parallel Ninja build for tools
cmake -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -B build-tools
# Use build-tools/compile_commands.json with the rewriter
```

### Meson

```bash
meson setup build
# compile_commands.json is automatically generated in build/
```

### Bear (for Make-based projects)

```bash
# Install Bear: https://github.com/rizsotto/Bear
bear -- make
# compile_commands.json is generated in current directory
```

### Ninja

```bash
ninja -C build -t compdb > build/compile_commands.json
```

## Usage

### Basic Usage

```bash
# Run on all files in compile_commands.json
./scripts/run_rewriter.py -p /path/to/build | ./scripts/apply_edits.py --base-dir /path/to/build

# Run on specific source directories only
./scripts/run_rewriter.py -p build src/ include/ | ./scripts/apply_edits.py --base-dir build
```

### Filter by Path Pattern

Use `--path-filter` with a substring to process only matching files:

```bash
# Only process files containing "src/core/" in their path
./scripts/run_rewriter.py -p build --path-filter "src/core/" | ./scripts/apply_edits.py --base-dir build
```

### Disable Specific Transformations

```bash
# Disable structured bindings transformation
./scripts/run_rewriter.py -p build --tool-args="--structured-bindings=false" | ./scripts/apply_edits.py --base-dir build

# Run only the .contains() transformation
./scripts/run_rewriter.py -p build --tool-args="--only=contains" | ./scripts/apply_edits.py --base-dir build
```

### Verbose Output

```bash
# Show progress
./scripts/run_rewriter.py -p build -v src/ 2>&1 | tee /tmp/edits.txt
./scripts/apply_edits.py --base-dir build < /tmp/edits.txt
```

## Available Transformations

- `.contains()` for associative containers
- Structured bindings for range-for loops
- Iterator loops to range-for
- DISALLOW_COPY_AND_ASSIGN replacement

All transformations are enabled by default. Use `--flag=false` to disable specific ones,
or `--only=<list>` to run only specific transformations.

See [TRANSFORMS.md](TRANSFORMS.md) for the complete list of command-line flags,
before/after examples, supported containers, and edge cases.

## Troubleshooting

### "compile_commands.json not found"

Make sure you've generated the compilation database. See the
"Generating compile_commands.json" section above.

### "No files found matching..."

- Check that the path filter matches your file paths
- Use `-v` for verbose output to see which files are being processed
- Try running without a path filter first

### Transformations not applying

- The tool only transforms code, not macro expansions
- Some patterns may not match due to unusual formatting
- Use `-v` to see error messages from the tool

## Compatibility

The transformed code uses C++20 features. See [TRANSFORMS.md](TRANSFORMS.md) for
minimum compiler requirements.

## Building from Source

This tool is built as part of the CEF (Chromium Embedded Framework) project.
See the CEF repository for build instructions.

---

### Overview (`tools/debug/ax_viewport_collapse/README.md`)

# ax_viewport_collapse Debug Tools

Manual verification tools for the `ax_viewport_collapse` CefBrowserSettings feature.
These connect to a running cefclient via CDP to inspect the accessibility tree.

## Prerequisites

```
python3 -m pip install websocket-client
```

## Usage

### 1. Launch cefclient with remote debugging

```
cefclient.exe --remote-debugging-port=9222 --remote-allow-origins=* --ax-viewport-collapse
```

The `--ax-viewport-collapse` flag maps to `CefBrowserSettings.ax_viewport_collapse = STATE_ENABLED` in cefclient.

To load the test page directly:

```
cefclient.exe --remote-debugging-port=9222 --remote-allow-origins=* --ax-viewport-collapse --url=file:///<path>/test_viewport_collapse.html
```

### 2. Run the verification script

```
python3 verify_viewport_collapse.py
```

Or navigate to a URL first:

```
python3 verify_viewport_collapse.py --url https://example.com
```

### Options

| Flag | Description |
|------|-------------|
| `--host` | CDP host (default: `127.0.0.1`) |
| `--port` | CDP port (default: `9222`) |
| `--url` | Navigate to URL before fetching tree |
| `--raw` | Print full JSON response instead of summary |

### Comparing with/without collapse

Run two cefclient instances on different ports:

```
cefclient.exe --cache-path=<path1> --remote-debugging-port=9222 --remote-allow-origins=* --ax-viewport-collapse
cefclient.exe --cache-path=<path2> --remote-debugging-port=9223 --remote-allow-origins=*
```

```
python3 verify_viewport_collapse.py --port 9222 --raw > with.json
python3 verify_viewport_collapse.py --port 9223 --raw > without.json
diff with.json without.json
```

### Expected output (with collapse enabled)

```
AX Tree Summary
============================================================
Total nodes returned:  77
  Ignored:             3
  Full (with children):70
  Summary (collapsed): 4

Collapsed summary nodes (off-screen landmarks/headings):
------------------------------------------------------------
  region: "Content preferences"
  region: "Audio quality"
  region: "Display"
  region: "Storage"
```

Off-screen landmark sections appear as leaf nodes with role + name only. In-viewport nodes are fully serialized with children.

## Files

- `verify_viewport_collapse.py` — CDP script that calls `Accessibility.getFullAXTree()` and prints a summary or raw JSON
- `test_viewport_collapse.html` — Test page with 6 landmark sections, 2 in viewport and 4 pushed off-screen by a spacer

---

### Overview (`libcef_dll/bootstrap/installer/testdata/README.md`)

# CEF Installer Test Data

This directory contains test fixtures for the CEF installer integration tests.

## Test Certificate

The `test_signing.pfx` file contains a self-signed code signing certificate
used for testing catalog signature verification.

**Important:** This certificate is NOT trusted by Windows. Tests use
`SetSignatureTestingMode(true)` to accept signatures from untrusted roots
when the thumbprint matches.

### Files

- `test_signing.pfx` - PKCS#12 file with certificate and private key
  - Password: `test`
- `test_signing.cer` - Public certificate only (DER format)
- `test_thumbprint.txt` - SHA1 thumbprint of the certificate

### Regenerating the Certificate

If the certificate needs to be regenerated (e.g., for a longer validity period):

```powershell
.\generate_test_cert.ps1
```

Note: The certificate has a 100-year validity period to avoid test failures
due to expiration.

## XZ Multi-Block Test Fixtures

These `.tar.xz` archives are used by `InstallerXzIndexTest`,
`InstallerParallelXzTest`, and `ExtractTarXzIntegrationTest` to test XZ index
parsing, parallel block decompression, and single-threaded fallback paths.

### Files

- `small_single.tar.xz` - Tiny single-block archive (1 block, ~276 bytes)
  - Contains one file: `hello.txt` ("Hello CEF\n")
  - Created with default xz settings (no `--block-size`)

- `single_block.tar.xz` - Medium single-block archive (1 block, ~920 bytes)
  - Contains 20 generated files (4 KB each) across 3 directories
  - Created with default xz settings (no `--block-size`)
  - Used for single-block fallback tests

- `multi_block_4.tar.xz` - Multi-block archive (30 blocks, ~11 KB)
  - Contains 20 generated files (4 KB each) across 3 directories
  - Created with `--block-size=4096` (4 KB blocks)
  - Used for parallel extraction and XZ index parsing tests

- `multi_block_large.tar.xz` - Larger multi-block archive (37 blocks, ~15 KB)
  - Contains 50 generated files (4 KB each) across 3 directories
  - Created with `--block-size=8192` (8 KB blocks)
  - Used for larger parallel extraction and thread-count limit tests

All archives use xz compression level 6 (default) with LZMA2 filter.

### Regenerating the Fixtures

Requires `xz.exe` (XZ Utils for Windows). Set the `XZ_EXE` environment
variable to the path of `xz.exe`.

```bash
python generate_fixtures.py [--xz-exe PATH]
```

**Important:** The archives contain deterministic content generated by
`generate_fixtures.py`. Regenerating will produce byte-identical archives
only if the same version of xz is used. Block counts may vary slightly
with different xz versions but should always meet the minimum requirements
(1 block for single-block fixtures, 4+ blocks for multi-block fixtures).

---

###  Config.Yml (`docs/_config.yml`)

title: CEF Documentation
description: Chromium Embedded Framework documentation
theme: jekyll-theme-minimal

---

### Api Versioning (`docs/api_versioning.md`)

This page explains CEF API versioning.

**Contents**

- [Overview](#overview)
- [Usage in Pull Requests](#usage-in-pull-requests)
- [Implementation](#implementation)
  - [Number Format](#number-format)
  - [Macros](#macros)
  - [ABI Guidelines](#abi-guidelines)
  - [Test Coverage](#test-coverage)
  - [Supported Versions](#supported-versions)

---

# Overview

The CEF library/framework exports an application binary interface (ABI) that is consumed by client applications. Historically this ABI has been unversioned meaning that any change in [CEF major/minor version](branches_and_building.md#version-number-format) would require a recompilation of the client application. Given the long release cycles for many client applications this could mean users being stuck at an old/insecure Chromium version for an extended period of time.

To address this and related issues we have introduced the concept of CEF API versioning. API versioning allows applications built for one Stable API version to run with all past and future CEF binaries that also support that version (see "Supported Versions" below).

CEF API versioning has three levels:

* Legacy API. API that existed prior to 2025 is grandfathered in as Stable API without an explicitly assigned version number.
* Versioned API. Stable API introduced in 2025 and later that is explicitly assigned a version number.
* Experimental API. API introduced in 2025 and later that is explicitly marked as "experimental" (see "Macros" below).

Stable API is guaranteed to provide back/forward ABI compatibility and a fixed C/C++ API within a specific (supported) range of binary builds. Developers that wish to update CEF/Chromium separately from the client application should select this option by defining `CEF_API_VERSION=XXXYY` in their project configuration (see "Number Format" and "Test Coverage" below).

Experimental API provides access to additional/experimental functionality on top of the most recent Stable API version but comes with some limitations:

* It's tied to a specific CEF major/minor version build.
* It doesn't support back/forward ABI compatibility.
* It's excluded (compiled out) when a Stable API version is selected.

By default, client applications are built with Experimental API enabled (no explicit `CEF_API_VERSION` define). The `CEF_API_VERSION` definition, in combination with certain macros (see "Macros" below), is used to customize the available C/C++ API as seen by the C/C++ compiler. Client applications and libcef_dll_wrapper must be recompiled if the `CEF_API_VERSION` definition changes.

API versioning does not does not guarantee behavioral compatibility, particularly when moving between major Chromium versions. App developers are advised to perform their own testing before rolling out any particular combination of binaries.

# Usage in Pull Requests

Project contributors use [pull requests](contributing_with_git.md#working-with-pull-requests) to propose CEF code changes. Any API changes in pull requests should follow the Implementation guidelines laid out below and use the `CEF_EXPERIMENTAL` placeholder value in C/C++ header files.

API changes may become Stable (be assigned a version) if explicitly approved by the CEF admin. API approved for Stable can use the `CEF_NEXT` placeholder value instead of `CEF_EXPERIMENTAL` in pull requests. This value will be converted to a specific/new CEF API version by the CEF admin prior to upstream merge (see example [here](https://github.com/chromiumembedded/cef/issues/3836#issuecomment-2587791506)).

# Implementation

The CEF library/framework exports a [C API](using_the_capi.md) that isolates the user from the CEF runtime and code base. The libcef_dll_wrapper project, which is distributed in source code form as part of the binary release, wraps this exported C API in a C++ API that is then linked into the client application. The code for this C/C++ API translation layer is automatically generated by the [translator tool](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt).

At runtime the client application reports the configured `CEF_API_VERSION` to the CEF library/framework via the first call to [cef_api_hash](https://github.com/chromiumembedded/cef/blob/master/include/cef_api_hash.h#L128) (performed internally by libcef_dll_wrapper). This is a global value that modifies the library/framework runtime behavior and cannot be changed after initial configuration. All API surface (enums, structs, etc.) must match the configured API version or otherwise the application will crash with a fatal runtime error.

Each API version has an associated set of API hashes. The [version_manager.py tool](https://github.com/chromiumembedded/cef/blob/master/tools/version_manager.py#L383) verifies API hashes at build time by reading and parsing all header files that contribute to the exported C API at that particular version. An API hash mismatch may occur during the `cef_create_projects` build step if the exported C API for an existing version has changed in an unexpected/unsupported way. This is considered a fatal build error and should be resolved before proceeding (see example [here](https://github.com/chromiumembedded/cef/issues/3836#issuecomment-2587767028)).

## Number Format

The CEF API version number format is `XXXZZ` where:

* `XXX` is the CEF (and Chromium) major version (e.g. `133`)
* `ZZ` is an incremental number (e.g. `01`, `02`, etc) that gets reset to `00` when the CEF major version changes. This [becomes](branches_and_building.md#version-number-format) the CEF minor version.

This format is incremental to work with logical operators and based on the [CEF version](branches_and_building.md#version-number-format) at which it was first introduced. New version numbers are generated by the [version_manager.py tool](https://github.com/chromiumembedded/cef/blob/master/tools/version_manager.py#L383) (see "Usage in Pull Requests" above).

By default, client applications are built with Experimental API enabled (no explicit `CEF_API_VERSION` define). Client applications can select a Stable API version by defining `CEF_API_VERSION=XXXYY` in their project configuration (see "Test Coverage" below).

## Macros

Stable and Experimental API is explicitly tagged in C/C++ header files using CEF versioning macros provided by [cef_api_hash.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_api_hash.h#L108). API without explicit tags is considered Legacy API (see "Overview" above). In C++ header files, versioning information is additionally included in CEF metadata (the `/*--cef(...)--*/` comment). Stable API uses a specific version number and Experimental API uses the `CEF_EXPERIMENTAL` placeholder (see "Number Format" above).

CEF macros (for C/C++ headers) are as follows:

* `#if CEF_API_ADDED(XXXYY)` surrounds code added in version `XXXYY`.
* `#if CEF_API_REMOVED(XXXYY)` surrounds code removed in version `XXXYY`.
* `#if CEF_API_RANGE(XXXYY, XXXYZ)` surrounds code added in version `XXXYY` and removed in version `XXXYZ`.

CEF metadata (for classes/methods in C++ headers) is as follows:

* `added=XXXYY` marks classes/methods added in version `XXXYY`.
* `removed=XXXYY` marks classes/methods removed in version `XXXYY`.
* `added=XXXYY,removed=XXXYZ` marks classes/methods added in version `XXXYY` and removed in version `XXXYZ`.

For example, a C++ header might contain:

```cpp
#include "include/cef_api_hash.h"

///
/// Client handler.
///
/*--cef(source=client)--*/
class CefClientHandler : public virtual CefBaseRefCounted {
 public:
  // Other method declarations here...

#if CEF_API_ADDED(13305)
  ///
  /// Callback when something happens. Added in version 13305.
  ///
  /*--cef(added=13305)--*/
  virtual void OnSomething() = 0;
#endif
};
```

The new `OnSomething` callback will be available with Experimental API versions and Stable API versions >= `13305`. It will be unavailable (compiled out) client-side with Stable API versions < `13305`. See [cef_api_hash.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_api_hash.h#L108) for additional client-side macros.

The associated CEF library/framework (libcef) implementation might contain:

```cpp
#include "cef/libcef/common/api_version_util.h"

void CefClientImpl::OnSomething() {
  if (CEF_API_IS_ADDED(13305)) {
    handler->OnSomething();
  } else {
    // Default handling
  }
}
```

All API versions are supported on the library/framework side so it's necessary to check the runtime-configured value. The `CEF_API_IS_ADDED` macro shown above returns true if the configured value is >= `13305`. See [api_version_util.h](https://github.com/chromiumembedded/cef/blob/master/libcef/common/api_version_util.h) for additional libcef-side macros.

See "Test Coverage" below for additional usage examples.

## ABI Guidelines

ABI versioning requires strict guidelines for how API surface is defined and mutated across versions.

Enums:

* All enums that might change get a `_NUM_VALUES` value at the end.
* New values are added immediately before `_NUM_VALUES` (except in cases where the value is explicitly set).
* Old/deprecated values are renamed to `_DEPRECATED` (or `_REMOVED`) but not removed.

Structs:

* All structs get a `size_t size` member at the beginning.
* New members are added at the end.
* Old/deprecated members are renamed to `_deprecated` (or `_removed`) but not removed.
* Existing members never change type (old may be renamed and new added with the same name).

Member methods:

* Return value and parameters never change for existing methods.
* New methods are added at the end of the class.
* Old/deprecated members in the C API struct are given an opaque placeholder pointer type (`uintptr_t`) to preserve binary compatibility (memory layout) with older versions.
* The existing method may be deprecated and a new method added if return value or parameters need to change. C++ naming may use polymorphism (e.g. multiple `OnEvent` with different params) but C API should use numbering (e.g. `on_event` as the original, `on_event[2...N]` or `on_event_[VERSION]` as the replacement).

Static methods & functions:

* Return value and parameters never change for existing methods/functions.
* Ordering doesn't matter as these symbols are exported directly from the library/framework.
* The existing method/function may be deprecated and a new method/function added if return value or parameters need to change. C++ naming may use polymorphism (e.g. multiple `CefDoWork` with different params) but C API should use numbering (e.g. `cef_do_work` as the original, `cef_do_work[2...N]` or `cef_do_work_[VERSION]` as the replacement).

See [cef_types.h](https://github.com/chromiumembedded/cef/blob/master/include/internal/cef_types.h) and "Test Coverage" below for examples.

## Test Coverage

Test coverage has been added for API version compatibility. CEF sample apps (cefclient, cefsimple, ceftests) can be built with different Stable API versions as follows (see "Number Format" above):

* Add `cef_api_version=XXXYY` to `GN_DEFINES` when building CEF/Chromium from source code.
* Add `-D api_version=XXXYY` to the `cmake` command-line when building with a CEF binary distribution.

API version-related unit tests can be run with `ceftests --gtest_filter=ApiVersionTest.*`.

Examples of API versioning are available at [include/test/cef_api_version_test.h](https://github.com/chromiumembedded/cef/blob/master/include/test/cef_api_version_test.h) (C++ header), [libcef/common/test/api_version_test_impl.cc](https://github.com/chromiumembedded/cef/blob/master/libcef/common/test/api_version_test_impl.cc) (libcef implementation) and [tests/ceftests/api_version_unittest.cc](https://github.com/chromiumembedded/cef/blob/master/tests/ceftests/api_version_unittest.cc) (client implementation). An explanation of the associated C API headers and C++ wrapper code generated by the [translator tool](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt) can be found [here](https://bitbucket.org/chromiumembedded/cef/pull-requests/852#comment-580301235).

## Supported Versions

API versioning support was added in M133 (January 2025). Newer CEF versions may occasionally drop support for older API versions (see example [here](https://github.com/chromiumembedded/cef/issues/3836#issuecomment-2483837347)). This may occur on a schedule (e.g. annually), or as a result of incompatible Chromium changes breaking existing APIs in irresolvable ways. When this occurs it will be clearly communicated and likely supported by shared installers.

---

### Architecture (`docs/architecture.md`)

This page provides an overview of the CEF architecture.

**Contents**

- [Overview](#overview)
- [Dependencies](#dependencies)
- [Versions](#versions)
- [History](#history)
- [Modern Architecture](#modern-architecture)
- [Common API Usage](#common-api-usage)
- [C Wrapper API](#c-wrapper-api)
- [CEF1 (Discontinued)](#cef1-discontinued)
  - [API Usage](#api-usage)
  - [Threading Considerations](#threading-considerations)
  - [Implementation Details](#implementation-details)
- [CEF2 (Discontinued)](#cef2-discontinued)
- [CEF3](#cef3)
  - [API Usage](#api-usage)
  - [Process Considerations](#process-considerations)
  - [Threading Considerations](#threading-considerations)
  - [Implementation Details](#implementation-details)
    - [Alloy Runtime Classes](#alloy-runtime-classes)
    - [Chrome Runtime Classes](#chrome-runtime-classes)

---

# Overview

The Chromium Embedded Framework (CEF) is an open source project founded by Marshall Greenblatt in 2008 to develop a Web browser control based on the [Google Chromium](http://www.chromium.org/Home) project. CEF currently supports a range of programming languages and operating systems and can be easily integrated into both new and existing applications. It was designed from the ground up with both performance and ease of use in mind. The base framework includes C and C++ programming interfaces exposed via native libraries that insulate the host application from Chromium and Blink implementation details. It provides close integration between the browser control and the host application, which can optionally control resource loading, navigation, context menus, printing, JavaScript bindings and more, while taking advantage of the same performance and HTML5 technologies available in the Google Chrome Web browser.

See the project [README.md](https://github.com/chromiumembedded/cef/blob/master/README.md) for additional introductory material.

# Dependencies

The CEF project depends on a number of other projects maintained by third parties. The major projects that CEF depends on are:

  * [Chromium](http://www.chromium.org/Home) - Provides general functionality like network stack, threading, message loop, logging and process control needed to create a fully functional Web browser. Implements "platform" code that allows Blink to communicate with V8 and Skia. Many Chromium design documents can be found at http://dev.chromium.org/developers.
  * [Blink](https://www.chromium.org/blink) (formerly WebKit) - The rendering implementation used by Chromium. Provides DOM parsing, layout, event handling, rendering and HTML5 JavaScript APIs. Some HTML5 implementations are split between the Blink and Chromium code bases.
  * [V8](https://developers.google.com/v8/) - JavaScript engine.
  * [Skia](https://skia.org/) - 2D graphics library used for rendering non-accelerated content. More information on how Chromium integrates Skia is available [here](http://www.chromium.org/developers/design-documents/graphics-and-skia).
  * [Angle](https://chromium.googlesource.com/angle/angle/+/master/README.md) - 3D graphics translation layer for Windows that converts GLES calls to DirectX. More information about accelerated compositing is available [here](http://dev.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome).

# Versions

There have been three versions of CEF to date.

  * CEF1 - Single process implementation using the Chromium WebKit API (now discontinued).
  * CEF2 - Multi process implementation built on the Chromium browser (now discontinued).
  * CEF3 - Multi process implementation using either the [Chromium Content API](http://www.chromium.org/developers/content-module/content-api) (called the "Alloy runtime") or the complete Chrome UI (called the "Chrome runtime").

Only the CEF3 version is currently developed and supported. See the "History" and "Modern Architecture" sections below for background and the [Branches And Building](branches_and_building.md) page for current development information.

# History

In 2008, when the CEF project started, Chromium was a monolithic application built on top of Apple's [WebKit](https://webkit.org/) rendering engine. Google maintained an in-tree variant of WebKit (called the [Chromium WebKit API](https://www.youtube.com/watch?v=JFzC_Gx76E8)) that added additional functionality specific to Chromium. The first version of CEF (called CEF1) was implemented on top of this Chromium WebKit API and used the default single-process application model supported by WebKit1 at that time (for more details on CEF1 architecture see the "CEF1" section below).

Use of the Chromium WebKit API came with some known limitations. For example, that API layer did not support the multi-process model that was the basis for most of Google Chrome's [stability and security advantages](https://chromium.googlesource.com/playground/chromium-org-site/+/refs/heads/main/developers/design-documents/multi-process-architecture/index.md). It also lacked many of the UI features that were becoming necessary to support new web platform features (like device selection dialogs, permissions management, etc). We therefore began a new effort, in 2010, to reimplement CEF (called CEF2) on top of the fully-featured but monolithic Chromium browser UI. The lack of internal API boundaries in the Chromium code at that time made it necessary for us to take an "all or nothing" approach. If we could create a CEF browser window based on the complete Chrome UI we would effectively gain access to all of Chrome's capabilities "for free" (for more details on CEF2 architecture see the "CEF2" section below).

Google began acknowledging the validity of the embedded use case for Chromium in 2010 and started work on new internal API boundaries to make embedding easier. The [Chromium Content API](http://www.chromium.org/developers/content-module/content-api), which encapsulated the multi-process application model and provided stub implementations for most web platform features, reached a development stage in late 2011 where it was a viable option for Chromium embedders like CEF. It still didn't provide all of the features that we might like, but it was a "supported" API layer. We therefore abandoned the CEF2 effort in early 2012 and focused our efforts instead on the Content API as the more viable embedding option. The existing CEF1 API, which was strongly dependent on WebKit1 and the single-process model, could not be directly ported to the Content API. A new CEF API (called CEF3), with substantial breaking API changes and multi-process support, was released in early 2013 (for more details on CEF3 architecture see the "Modern Architecture" and "CEF3" sections below).

Also in 2013, Google decided to [fork the WebKit project](https://blog.chromium.org/2013/04/blink-rendering-engine-for-chromium.html). After renaming it to Blink they removed many of the API boundaries that had previously existed between Chromium and WebKit and effectively deleted the Chromium WebKit API. The multi-process architecture, which was optional in WebKit1, was now a requirement with Chromium/Blink. CEF1, which depended on the Chromium WebKit API, no longer had a viable future and CEF3 became the only path forward.

Fast forward another 7 years, to 2020, and the Chromium architecture has again changed substantially. A lot of effort has been spent to define clear architectural layers (sometimes called [components](https://www.chromium.org/developers/design-documents/cookbook/)) in the Chromium/Blink source code. New platforms and new embedders have entered the Chromium ecosystem. And yet, many features desired by CEF users remain stubbornly out of reach in the Chrome UI layer. With this new, more modern, version of Chromium, we decided it was time to revisit our goals from CEF2 and create a new CEF version based on the Chrome UI layer (now called the "Chrome runtime" in CEF3). Continue to the "Modern Architecture" section for details.

# Modern Architecture

The modern Chromium code base is composed of architectural layers, with the primary application layers being "content" (for the [Content API](http://www.chromium.org/developers/content-module/content-api)) and "chrome" (for the Chrome UI layer). The "content" layer includes [WebContents](https://source.chromium.org/chromium/chromium/src/+/master:content/public/browser/web_contents.h) as the primary browser object and provides implementations for most of the generic web platform and application/process management functionality. The "chrome" layer includes [Browser](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/browser.h) as the primary browser object and provides implementations for many advanced features (including datalist/autofill, extensions, gamepad, webhid, webmidi, etc.), along with standard Chrome UI toolbars and dialogs for device selection, user permissions, settings, etc.

For historical reasons (outlined above), CEF browser windows have been based on the "content" layer WebContents object since the introduction of CEF3 in 2013. Adding support for additional "chrome" layer features in that architecture was a serious effort because it involved careful understanding and cherry-picking of the related functionality from "chrome" code into the CEF code base. Over time we have added dependencies on the "chrome" layer targets to support some features in CEF (such and extensions, PDF viewer and print preview) and to avoid code duplication. As a result, CEF3 binaries in modern times already contained most/all of the code that would be required to launch a stand-alone "chrome" Browser window, but simply lacked the mechanism to do so.

In 2020 we launched a [new effort](https://github.com/chromiumembedded/cef/issues/2969) to implement the CEF3 API on top of a fully-featured "chrome" Browser window. To be usable in existing CEF3 client applications the "chrome" window needed to support a large subset of CEF3's existing callbacks/intercepts (e.g. loading progress, network requests, etc.), and be inserted into the existing [Views framework](https://www.chromium.org/developers/design-documents/chromeviews/) structure. At the same time, it was necessary to substantially refactor the internal CEF (libcef) code to extract functionality that was common to both the old WebContents-based approach and the new Browser-based approach. As part of this refactoring we renamed the existing "content" layer implementation to the "Alloy runtime" (where Alloy = Chrome + other stuff) and named the new "chrome" layer implementation as the "Chrome runtime". Proceed to the "CEF3" section below for additional feature and implementation details.

# Common API Usage

All versions of CEF expose a simple, easy-to-use API designed to insulate users from the underlying Chromium and Blink code complexity. Common usage is as follows:

1. Initialize CEF by calling CefInitialize().

2. Perform work on the UI message loop by calling CefRunMessageLoop() or CefDoMessageLoopWork().

3. Create a browser window by calling CreateBrowser() or CreateBrowserSync() and passing in a CefClient instance.

4. Shut down CEF by calling CefShutdown() before the application exits.

# C Wrapper API

The libcef shared library exports a C API that isolates the user from the CEF runtime and code base. The libcef\_dll\_wrapper project, which is distributed in source code form as part of the binary release, wraps this exported C API in a C++ API that is then linked into the client application. The code for this C/C++ API translation layer is automatically generated by the [translator](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt) tool. Direct usage of the C API is described on the [Using The CAPI](using_the_capi.md) page.

# CEF1 (Discontinued)

CEF1 was the initial version of CEF first released in 2008. It was discontinued in 2013 when Google forked the WebKit project and subsequently deleted the Chromium WebKit API. See the "History" section above for additional details.

The single process architecture used by CEF1 integrates Chromium and WebKit directly into the client application. Advantages to the single process architecture included reduced memory usage and closer integration with the client application. For example, having the renderer running in the same process allowed JavaScript bindings to synchronously communicate between client code and renderer code. Disadvantages included [reduced performance](https://github.com/chromiumembedded/cef/issues/304) with certain types of accelerated content, [crashes](https://github.com/chromiumembedded/cef/issues/242) due to plugins like Flash running in the same process, and lack of support for application [security and stability features](https://chromium.googlesource.com/playground/chromium-org-site/+/refs/heads/main/developers/design-documents/multi-process-architecture/index.md) that required a multi-process architecture.

## API Usage

Below is an overview of the main CEF1 interfaces and their uses. Since CEF1 is discontinued we no longer provide detailed usage information.

  * [CefApp](http://magpcss.org/ceforum/apidocs/projects/(default)/CefApp.html) - This interface is passed to CefInitialize() and allows the application to customize global functionality like resource loading and proxy handling.
  * [CefClient](http://magpcss.org/ceforum/apidocs/projects/(default)/CefClient.html) - This interface is passed to CefCreateBrowser() or CefCreateBrowserSync() and acts as the connection between an individual CEF browser instance and the client application. Additional interfaces for request handling, display handling, etc. are exposed via this interface.
  * [CefBrowser](http://magpcss.org/ceforum/apidocs/projects/(default)/CefBrowser.html) - Exposes capabilities provided by the browser. This includes back/forward navigation, source retrieval, request loading, etc. A single CefBrowser may have one or more child [CefFrame](http://magpcss.org/ceforum/apidocs/projects/(default)/CefFrame.html) objects.

## Threading Considerations

CEF1 includes UI, IO and FILE threads. The UI thread creates browser windows and is used for all interaction with WebKit and V8. The IO thread is used for handling schema and network requests. The FILE thread is used for the application cache and other miscellaneous activities.

When using CEF1 you should keep the following threading considerations in mind:

  * Do not perform blocking operations on the UI thread. This can lead to serious performance issues.
  * The UI thread will be the same as the main application thread if CefInitialize() is called with a CefSettings.multi\_threaded\_message\_loop value of false.
  * All WebKit and V8 interation must take place on the UI thread. Consequently, some CEF API functions can only be called on the UI thread. Functions that have this limitation will be documented accordingly in the associated CEF header file.
  * The [CefPostTask](http://magpcss.org/ceforum/apidocs/projects/(default)/(_globals).html#CefPostTask(CefThreadId,CefRefPtr<CefTask>)) method can be used to post tasks asnychronously between the various threads.

## Implementation Details

CEF1 has the following major implementation classes:

  * CefContext - Represents the global CEF context. A single CefContext object is created by CefInitialize() and destroyed by CefShutdown().
  * CefProcess - Used by CefContext to create and manage the CEF threads.
  * BrowserWebKitInit - Manages the global WebKit environment as exposed by the Chromium WebKit API.
  * WebViewHost - Provides the native window "wrapper" implementation for a WebView. This class extends WebWidgetHost which provides functionality shared in common with popup widgets (like select menus) on some platforms.
  * CefBrowserImpl - Implements the CefBrowser interface, creates the WebViewHost and provides the glue code for a single browser instance.
  * BrowserWebViewDelegate - Implements the WebKit interfaces that provide communication between CefBrowserImpl and the underlying WebView.

# CEF2 (Discontinued)

CEF2 was an effort to reimplement the CEF1 API on top of the Chrome browser UI as it existed in 2010. CEF2 was discontinued when Chromium announced support for the Content API. Information about CEF2 can be found in the "History" section above and [here](http://magpcss.org/ceforum/viewtopic.php?f=10&t=122) on the CEF Forum.

# CEF3

CEF3 has been the recommended and supported version of CEF since January 2013. It uses the same multi process architecture as the Chromium Web browser via either the [Chromium Content API](http://www.chromium.org/developers/content-module/content-api) (called the "Alloy runtime") or the complete Chrome UI (called the "Chrome runtime"). This architecture provides a number of advantages over the single process architecture used by CEF1:

  * Support for multi-process run mode (with related [stability and security advantages](https://chromium.googlesource.com/playground/chromium-org-site/+/refs/heads/main/developers/design-documents/multi-process-architecture/index.md)).
  * More code sharing with the Chromium browser.
  * Improved performance and less breakage due to use of the "supported" code path.
  * Faster access to new features.

In most cases CEF3 will have the same performance and stability characteristics as the Chromium Web browser. Both the Alloy runtime and the Chrome runtime support modern web platform features and provide the safety/security expected from an up-to-date Chromium-based browser. The Chrome runtime, which was introduced in 2020, adds implementations for many advanced features (including datalist/autofill, extensions, gamepad, webhid, webmidi, etc.), along with standard Chrome UI toolbars and dialogs for device selection, user permissions, settings, etc. At the time of writing, the Chrome runtime requires use of the [Views framework](https://www.chromium.org/developers/design-documents/chromeviews/) in CEF client applications and does not support off-screen rendering. A current list of open issues specific to the Chrome runtime can be found [here](https://github.com/chromiumembedded/cef/issues?q=is%3Aissue+is%3Aopen+label%3Achrome).

Starting with the M125 release (mid-2024) the Alloy runtime has been [split](https://github.com/chromiumembedded/cef/issues/3681) into separate style and bootstrap components. Both Chrome style and Alloy style browsers/windows can now be created while using the Chrome bootstrap. The Alloy bootstrap has been [removed](https://github.com/chromiumembedded/cef/issues/3685) starting with the M128 release.

## API Usage

See the [General Usage](general_usage.md) page for detailed API usage instructions.

## Process Considerations

See the [Processes](general_usage.md#processes) section of the [General Usage](general_usage.md) page for details.

## Threading Considerations

See the [Threads](general_usage.md#threads) section of the [General Usage](general_usage.md) page for details.

## Implementation Details

For an implementation overview see the "Modern Architecture" section above. 

Shared CEF library/runtime classes use the Cef prefix. Classes that implement the Alloy or Chrome runtime use the Alloy or Chrome prefixes respectively. Classes that extend an existing Chrome-prefixed class add the Cef or Alloy suffix, thereby following the existing naming pattern of Chrome-derived classes.

### Alloy Runtime Classes

Alloy runtime bootstrap was [removed](https://github.com/chromiumembedded/cef/issues/3685) in M128 (mid-2024) and Alloy runtime style is now supported using the Chrome runtime bootstrap. Alloy runtime style is based on the "content" layer and has the following major implementation classes:

  * [AlloyBrowserHostImpl](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/alloy/alloy_browser_host_impl.h) - Implements the CefBrowser and CefBrowserHost interfaces in the browser process. Provides the glue code and implements interfaces for communicating with the RenderViewHost.

### Chrome Runtime Classes

Chrome runtime bootstrap and style is based on the "chrome" layer and has the following major implementation classes:

  * [ChromeMainDelegateCef](https://github.com/chromiumembedded/cef/blob/master/libcef/common/chrome/chrome_main_delegate_cef.h) - Implements the common process bootstrap logic.
  * [ChromeContentClientCef](https://github.com/chromiumembedded/cef/blob/master/libcef/common/chrome/chrome_content_client_cef.h) - Implements the Content API callbacks that are common to all processes.
  * [CefContext](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/context.h) - Represents the global CEF context in the browser process. A single CefContext object is created by CefInitialize() and destroyed by CefShutdown().
  * [ChromeBrowserMainExtraPartsCef](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h) - Implements the browser process bootstrap logic.
  * [ChromeContentBrowserClientCef](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/chrome/chrome_content_browser_client_cef.h) - Implements the Content API callbacks for the browser process.
  * [ChromeBrowserHostImpl](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/chrome/chrome_browser_host_impl.h) - Implements the CefBrowser and CefBrowserHost interfaces in the browser process. Provides the glue code and implements interfaces for communicating with the RenderViewHost.
  * [ChromeContentRendererClientCef](https://github.com/chromiumembedded/cef/blob/master/libcef/renderer/chrome/chrome_content_renderer_client_cef.h) - Implements the Content API callbacks for the render process.
  * [CefBrowserImpl](https://github.com/chromiumembedded/cef/blob/master/libcef/renderer/browser_impl.h) - Implements the CefBrowser interface in the render process. Provides the glue code and implements interfaces for communicating with the RenderView.
  * [ChromeBrowserDelegate](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/chrome/chrome_browser_delegate.h) - Interface injected into Chrome's [Browser](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/browser.h) object (via [patch files](https://github.com/chromiumembedded/cef/blob/master/patch/README.txt)) to support callbacks into CEF code.
  * [ChromeBrowserFrame](https://github.com/chromiumembedded/cef/blob/ecdfd467f84da9bb6ef57eb4fcb2778fdef5e07a/libcef/browser/chrome/views/chrome_browser_frame.h) - Widget for a Views-hosted Chrome browser.

An overview of the Chrome Browser object model is also available [here](https://github.com/chromiumembedded/cef/blob/ecdfd467f84da9bb6ef57eb4fcb2778fdef5e07a/libcef/browser/chrome/views/chrome_browser_frame.h).

---

### Automated Build Setup (`docs/automated_build_setup.md`)

This page describes the setup of an automated build system for CEF.

**Contents**

- [Overview](#overview)
- [Services](#services)
- [Execution Steps](#execution-steps)
  - [1\. Change Trigger](#1-change-trigger)
  - [2\. Platform Builder](#2-platform-builder)
  - [3\. Artifact Publisher](#3-artifact-publisher)
- [Platform Build Configurations](#platform-build-configurations)
  - [Linux Configuration](#linux-configuration)
  - [MacOS Configuration](#macos-configuration)
  - [Windows Configuration](#windows-configuration)

---

# Overview

CEF provides tools for automatically downloading, building and packaging Chromium and CEF source code. These tools are the recommended way of building CEF locally and can also be integrated with an automated build system. Examples of automated build systems for CEF include <https://cef-builds.spotifycdn.com/index.html> hosted by Spotify. This document outlines how to build a system similar to Spotify's. For general CEF build instructions see the [Branches And Building](branches_and_building.md) page.

# Services

An automated build system tracks changes to a CEF branch, automatically builds a new version of CEF when changes are detected, and uploads the resulting artifacts (CEF binary files) to an Internet or Intranet Website.

The following high-level services are necessary for an automated build system:

1. Build execution service. Used to perform the CEF automated builds using agents running on different OS platforms. For example, a build system like [TeamCity](http://www.jetbrains.com/teamcity/) or [Jenkins](http://jenkins-ci.org/).
2. Artifact storage service. Used to store artifacts referenced and generated by the build agents. For example, a shared file system or a storage system like [Artifactory](https://www.jfrog.com/artifactory/).
3. Artifact publishing service. Used to publish artifacts for download on the Intranet or Internet. Generally provides some form of distributed caching. For example, a cloud provider like [Amazon S3 + Cloudfront](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/MigrateS3ToCloudFront.html) or [Google Cloud Storage](https://cloud.google.com/storage/).

Setup of these specific services is outside the scope of this document. However, we will refer to the capabilities of these services in generic terms.

# Execution Steps

The reference build system works by executing the following steps in order:

## 1\. Change Trigger

Runs automatically at some interval (for example, once daily) to check if a new change has been committed to the CEF repository. The [GitHub REST API](https://docs.github.com/en/rest/branches/branches#get-a-branch) exposes an endpoint that can be queried to identify the most recent commit in a branch. For example, this will return the most recent commit for 2785 branch:

<https://api.github.com/repos/chromiumembedded/cef/branches/2785>

The resulting "commit.sha" value can then be compared to the last successful CEF build version to identify if a new build is required (e.g. a sha value of "1e15b7626244fa6c6455b7a24552664e4cc14fd3" from branch 2785 will match a build artifact file named "cef_binary_3.2785.\*.g1e15b76_\*.tar.bz2").

If artifacts are stored on a shared file system then languages like Python can access the file list directly. If artifacts are stored in Artifactory then see the [Artifactory REST API](https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API) documentation for instructions on how to retrieve a directory listing.

## 2\. Platform Builder

Initiated by the change trigger when a new commit is detected. A separate platform builder is configured for each supported build platform (linux32, linux64, macosx64, windows32, windows64). It executes a build on that platform and then uploads the resulting build artifact files to the storage service (shared file system, Artifactory, etc.).

See the "Platform Build Configurations" section below for recommended platform build configurations.

## 3\. Artifact Publisher

Initiated by the platform builder upon a successful build. It retrieves the list of build artifact files from the storage service and uses the [cefbuilds](https://github.com/chromiumembedded/cef/blob/master/tools/cefbuilds/) tools to compare against the index.json file generated by the previous run. When changes are detected it uploads the new changes to the publishing service (Amazon S3, GCS, etc.). The new index.json file is then stored for future reference.

In addition to generating [index.json](https://cef-builds.spotifycdn.com/index.json) files the [cefbuilds](https://github.com/chromiumembedded/cef/blob/master/tools/cefbuilds/) tools can also generate the [index.html](https://cef-builds.spotifycdn.com/index.html) file used by the Spotify builder (provide your own custom branding to cef_html_builder.py via the "branding" parameter). See the cef_json_builder_example.py and cef_html_builder.py files from the cefbuilds directory for sample usage.

# Platform Build Configurations

The following configurations are executed by the platform builder step. These are the recommended configurations for externally published artifacts but are not recommended for local builds. See the the [Branches And Building](branches_and_building.md) page for general build instructions.

These instructions are intended for use with the [currently supported release branches](branches_and_building.md#current-release-branches-supported). This page will be updated as build requirements change.

Lower-case values between %% (%download_dir%, %cef_branch%, etc.) must be provided by you.

## Linux Configuration

**What's Required**

- Linux Build Requirements as listed on the [Branches And Building](branches_and_building.md#current-release-branches-supported) page.
- At least 16GB of RAM and 200GB of free disk space.

We recommend building on Linux using a [Docker container](https://www.docker.com/resources/what-container). All architectures can be built using the same Linux container image with a configuration [as shown here](https://magpcss.org/ceforum/viewtopic.php?f=7&t=17776&p=46448#p54107) that utilizes Chromium's [install-build-deps.py](https://source.chromium.org/chromium/chromium/src/+/master:build/install-build-deps.py) script.

**64-bit Build Commands**

To build 64-bit CEF with a 64-bit Linux Docker image:

```sh
export GN_DEFINES="is_official_build=true use_sysroot=true symbol_level=1 is_cfi=false"
export CEF_ARCHIVE_FORMAT=tar.bz2
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --build-target=cefsimple --x64-build --with-pgo-profiles
```

**ARM Build Commands**

To build ARM CEF with a 64-bit Linux Docker image:

```sh
export CEF_INSTALL_SYSROOT=arm
export GN_DEFINES="is_official_build=true use_sysroot=true symbol_level=1 is_cfi=false use_thin_lto=false chrome_pgo_phase=0 use_vaapi=false"
export CEF_ARCHIVE_FORMAT=tar.bz2
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --build-target=cefsimple --arm-build
```

**ARM64 Build Commands**

To build ARM64 CEF with a 64-bit Linux Docker image:

```sh
export CEF_INSTALL_SYSROOT=arm64
export GN_DEFINES="is_official_build=true use_sysroot=true symbol_level=1 is_cfi=false use_thin_lto=false chrome_pgo_phase=0"
export CEF_ARCHIVE_FORMAT=tar.bz2
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --build-target=cefsimple --arm64-build
```

## MacOS Configuration

**What's Required**

- MacOS Build Requirements as listed on the [Branches And Building](branches_and_building.md#current-release-branches-supported) page.
- At least 16GB of RAM and 200GB of free disk space.

If Xcode is not installed to the default location then:

1\. Set the correct location using the `xcodeselect` tool.

2\. Set the `SDKROOT` environment variable:

```sh
export SDKROOT=$(xcrun -show-sdk-path -sdk macosx)
```

**64-bit Build Commands**

To build Intel 64-bit CEF on a Intel 64-bit MacOS host system:

```sh
export GN_DEFINES=is_official_build=true
export CEF_ARCHIVE_FORMAT=tar.bz2
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --x64-build --with-pgo-profiles
```

To build Intel 64-bit CEF on a ARM64 MacOS host system:

```sh
export GN_DEFINES=is_official_build=true
export CEF_ARCHIVE_FORMAT=tar.bz2
export CEF_ENABLE_AMD64=1
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --x64-build --with-pgo-profiles
```

**ARM64 Build Commands**

ARM64 builds require Xcode 12.2 and CEF branch 4280 or newer.

To build ARM64 CEF on an ARM64 MacOS host system:

```sh
export GN_DEFINES=is_official_build=true
export CEF_ARCHIVE_FORMAT=tar.bz2
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --arm64-build --with-pgo-profiles
```

To build ARM64 CEF on a Intel 64-bit MacOS host system:

```sh
export GN_DEFINES=is_official_build=true
export CEF_ARCHIVE_FORMAT=tar.bz2
export CEF_ENABLE_ARM64=1
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --arm64-build --with-pgo-profiles
```

## Windows Configuration

**What's Required**

- Visual Studio and Windows SDK versions as listed on the [Branches And Building](branches_and_building.md#current-release-branches-supported) page.
- At least 16GB of RAM and 200GB of free disk space.

Install the required Visual Studio sub-components by passing the following arguments to the Visual Studio installer:

```sh
$ PATH_TO_INSTALLER.EXE ^
--add Microsoft.VisualStudio.Workload.NativeDesktop ^
--add Microsoft.VisualStudio.Component.VC.ATLMFC ^
--includeRecommended
```

If building for ARM64 install the following additional sub-components:

```sh
$ PATH_TO_INSTALLER.EXE ^
--add Microsoft.VisualStudio.Component.VC.Tools.ARM64 ^
--add Microsoft.VisualStudio.Component.VC.MFC.ARM64 ^
--includeRecommended
```

If Visual Studio or Windows SDK is not installed to the default location then set environment variables like the following before executing automate-git.py:

```sh
set WIN_CUSTOM_TOOLCHAIN=1
set CEF_VCVARS=none
set GYP_MSVS_OVERRIDE_PATH=%vs_root%
set VS_CRT_ROOT=%vs_crt_root%
set SDK_ROOT=%sdk_root%
set PATH=%sdk_root%\bin\%sdk_version%\x64;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\bin\HostX64\x64;%vs_root%\VC\Redist\MSVC\%vc_redist_version%\x64\%vc_redist_crt%;%vs_root%\SystemCRT;%PATH%
set LIB=%sdk_root%\Lib\%sdk_version\um\%arch%;%sdk_root%\Lib\%sdk_version\ucrt\%arch%;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\lib\%arch%;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\atlmfc\lib\%arch%;%LIB%
set INCLUDE=%sdk_root%\Include\%sdk_version%\um;%sdk_root%\Include\%sdk_version%\ucrt;%sdk_root%\Include\%sdk_version%\shared;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\include;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\atlmfc\include;%INCLUDE%
```

The correct `PATH`, `LIB` and `INCLUDE` values for your installation can be determined by running the `vcvarsall.bat` script and passing in the desired architecture and SDK version.

See comments in [gclient_hook.py](https://github.com/chromiumembedded/cef/blob/2785/tools/gclient_hook.py#L54) for Windows custom toolchain requirements. VS + SDK can be packaged for distribution to build agents using a script like Chromium's [package_from_installed.py](https://source.chromium.org/chromium/chromium/tools/depot_tools/+/main:win_toolchain/package_from_installed.py).

**32-bit Build Commands**

To build 32-bit CEF on a 64-bit Windows host system:

```sh
set GN_DEFINES=is_official_build=true
set GYP_MSVS_VERSION=2022
set CEF_ARCHIVE_FORMAT=tar.bz2
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --with-pgo-profiles
```

**64-bit Build Commands**

To build 64-bit CEF on a 64-bit Windows host system:

```sh
set GN_DEFINES=is_official_build=true
set GYP_MSVS_VERSION=2022
set CEF_ARCHIVE_FORMAT=tar.bz2
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --x64-build --with-pgo-profiles
```

**ARM64 Build Commands**

To build ARM64 CEF on a 64-bit Windows host system:

```sh
set CEF_ENABLE_ARM64=1
set GN_DEFINES=is_official_build=true use_thin_lto=false chrome_pgo_phase=0
set GYP_MSVS_VERSION=2022
set CEF_ARCHIVE_FORMAT=tar.bz2
python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --build-target=cefsimple --arm64-build
```

---

### Branches And Building (`docs/branches_and_building.md`)

This page provides information about CEF branches and instructions for downloading, building and packaging source code.

**Contents**

- [Background](#background)
- [Development](#development)
- [Release Branches](#release-branches)
  - [Version Number Format](#version-number-format)
  - [Current Release Branches (Supported)](#current-release-branches-supported)
  - [Legacy Release Branches (Unsupported)](#legacy-release-branches-unsupported)
- [Building from Source](#building-from-source)
  - [Automated Method](#automated-method)
  - [Manual Downloading](#manual-downloading)
  - [Manual Building](#manual-building)
  - [Manual Packaging](#manual-packaging)
  - [Build Notes](#build-notes)

---

# Background

The CEF project is an extension of the Chromium project hosted at [chromium.org](https://www.chromium.org). CEF maintains development and release branches that track Chromium branches. CEF source code can be built manually or with automated tools.

# Development

Ongoing development of CEF occurs in the [CEF master branch](https://github.com/chromiumembedded/cef/tree/master). This location tracks the current [Chromium master branch](https://chromium.googlesource.com/chromium/src.git) and is not recommended for production use.

Current CEF master branch build requirements are as follows. See the [Master Build Quick Start](master_build_quick_start.md) page for a development build quick-start guide.

Windows Build Requirements | macOS Build Requirements | Linux Build Requirements |
|:---------------------------|:----------------------------|:-------------------------|
Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.28000.2270 SDK, Ninja | macOS 13.0+ deployment, 26.6+ build system w/ 27.0 base SDK (Xcode 27.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |

The following URLs should be used for downloading development versions of CEF.

  * CEF3 - <https://github.com/chromiumembedded/cef/tree/master>

CEF1 is no longer actively developed or supported. See the [CEF1 Retirement Plan](http://magpcss.org/ceforum/viewtopic.php?f=10&t=10647) for details.

# Release Branches

CEF branches are created to track each Chromium release milesone (MXX) branch. Users developing applications for production environments are encouraged to use release branches for the following reasons:

  * Binary CEF builds are tied to specific Chromium releases.
  * Release versions of CEF/Chromium are better tested and more appropriate for release applications.
  * Within a release branch the CEF API is "frozen" and generally only security/bug fixes are applied.
  * CEF release branches can include patches to Chromium/Blink source if necessary.
  * CEF master development won't interfere with consumer release schedules.

CEF release branches and associated platform build requirements are described below.

## Version Number Format

The CEF version number format was changed in 2019 to include more relevant information and to provide compatibility with the [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html) standard.

Newer CEF release version numbers have the format "X.Y.Z+gHHHHHHH+chromium-A.B.C.D" where:

* "X" is the CEF (and Chromium) major version (e.g. 73).
* "Y" is the CEF minor version. It's an incremental number that starts at 0 when a release branch is created and changes only when the CEF C/C++ API changes (see [Api Versioning](api_versioning.md) for details).
* "Z" is the CEF bugfix version. It's an incremental number that starts at 0 when a release branch is created and changes on each commit, with reset to 0 when "Y" changes.
* "gHHHHHHH" is the 7-character abbreviation for the Git commit hash. This facilitates lookup of the relevant commit history in Git.
* "A.B.C.D" is the Chromium version (e.g. 73.0.3683.75).

Older CEF release version numbers have the format X.YYYY.A.gHHHHHHH where:

  * "X" is the CEF major version (e.g. 3).
  * "YYYY" is the Chromium branch.
  * "A" is an incremental number representing the number of commits in the current branch. This is roughly equivalent to the SVN revision number but on a per-branch basis and assists people in quickly determining the order of builds in the same branch (for bug reports, etc).
  * "gHHHHHHH" is the 7-character abbreviation for the Git commit hash. This facilitates lookup of the relevant commit history in Git.

Detailed Chromium and CEF version information is available in the include/cef\_version.h header file which is created during the build process or by loading the "about:version" URL in a CEF-derived application.

## Current Release Branches (Supported)

CEF is currently tracking even-numbered Chromium milestone branches (new CEF branch every ~4 weeks, adjusted for holidays). Support for new branches begins when they enter the Chromium beta channel. Support for older branches ends when they exit the Chromium stable channel (after [2 weeks](https://developer.chrome.com/blog/chrome-two-week-release) as stable), unless that branch also qualifies for [extended](https://support.google.com/chrome/a/answer/16942104?hl=en) and/or [LTC/LTS](https://support.google.com/chrome/a/answer/11333726?hl=en) channels.

  * **Stable channel:** Every other Chromium milestone branch starting with M152. These branches receive broad security fixes for ~2 weeks after entering the stable channel.
  * **Extended channel:** Every fourth Chromium milestone branch starting with M152. These branches receive broad security fixes for ~8 weeks total (including time spent in stable).
  * **LTC/LTS channel:** Every 12th Chromium milestone branch starting with M160 (every sixth from M138-M150). These branches receive platform-agnostic security fixes for ~9 months total (including time spent in stable and/or extended).

The [Spotify automated builder](https://cef-builds.spotifycdn.com/index.html) provides CEF builds for supported branches. Updating CEF branches is currently a manual process so there will likely be a delay between [Chromium release announcements](http://googlechromereleases.blogspot.com/) and the availability of associated CEF builds. See the [Chromium release calendar](https://chromiumdash.appspot.com/schedule) for estimated Chromium release dates and versions.

| Channel |Release Branch | Version | Branch Date | Last Refresh  | Windows Build Requirements | macOS Build Requirements | Linux Build Requirements |
|:--------|:--------------|:--------|:------------|:--------------|:---------------------------|:----------------------------|:-------------------------|
| Beta     | [8078](https://github.com/chromiumembedded/cef/tree/8078) | 156              | Oct 2026    | Jan 4, 2027  | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.28000.2270 SDK, Ninja | macOS 13.0+ deployment, 26.6+ build system w/ 27.0 base SDK (Xcode 27.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| Extended | [7977](https://github.com/chromiumembedded/cef/tree/7977) | 152              | Aug 2026    | Oct 20, 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.7705 SDK, Ninja | macOS 13.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| LTC      | [7871](https://github.com/chromiumembedded/cef/tree/7871) | 150              | Jun 2026    | Apr 13, 2027 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.7705 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |

## Legacy Release Branches (Unsupported)

Legacy CEF builds are available from the [Spotify automated builder](https://cef-builds.spotifycdn.com/index.html) back to 2704 branch. Building legacy branches is not supported. If you choose to build a legacy branch you will need to solve any build errors on your own.

  * Newer legacy branches (within the past year) can often be built using the same tooling as current branches. You will need to (a) manually download depot_tools, (b) sync depot_tools to a revision that existed at the time of the branch, and (c) set the `DEPOT_TOOLS_UPDATE=0` environment variable to keep it from updating automatically.
  * Older legacy branches can potentially be built by downloading a CEF source archive at the desired branch from [here](https://github.com/chromiumembedded/cef/tags) and a Chromium source archive at the associated/required version from [here](https://gsdview.appspot.com/chromium-browser-official/), and then combining them to create the required directory structure.
  * See the Build Notes section at the end of this page for historical build details.

| Release Branch | Version | Branch Date | Windows Build Requirements | macOS Build Requirements | Linux Build Requirements |
|:---------------|:--------|:------------|:---------------------------|:----------------------------|:-------------------------|
| [8037](https://github.com/chromiumembedded/cef/tree/8037) | 154 | Sep 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.28000.2270 SDK, Ninja | macOS 13.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7922](https://github.com/chromiumembedded/cef/tree/7922) | 151 | Jul 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.7705 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7827](https://github.com/chromiumembedded/cef/tree/7827) | 149 | May 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.7705 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7778](https://github.com/chromiumembedded/cef/tree/7778) | 148 | Apr 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7727](https://github.com/chromiumembedded/cef/tree/7727) | 147 | Mar 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7680](https://github.com/chromiumembedded/cef/tree/7680) | 146 | Feb 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7632](https://github.com/chromiumembedded/cef/tree/7632) | 145 | Jan 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7559](https://github.com/chromiumembedded/cef/tree/7559) | 144 | Dec 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7499](https://github.com/chromiumembedded/cef/tree/7499) | 143 | Nov 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7444](https://github.com/chromiumembedded/cef/tree/7444) | 142 | Oct 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7390](https://github.com/chromiumembedded/cef/tree/7390) | 141 | Sep 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.3+ build system w/ 15.5 base SDK (Xcode 16.4), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7339](https://github.com/chromiumembedded/cef/tree/7339) | 140 | Aug 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 12.0+ deployment, 15.3+ build system w/ 15.5 base SDK (Xcode 16.4), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7258](https://github.com/chromiumembedded/cef/tree/7258) | 139 | Jul 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 12.0+ deployment, 15.2+ build system w/ 15.4 base SDK (Xcode 16.3), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7204](https://github.com/chromiumembedded/cef/tree/7204) | 138 | Jun 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 11.0+ deployment, 15.2+ build system w/ 15.4 base SDK (Xcode 16.3), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7151](https://github.com/chromiumembedded/cef/tree/7151) | 137 | May 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7103](https://github.com/chromiumembedded/cef/tree/7103) | 136 | Apr 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [7049](https://github.com/chromiumembedded/cef/tree/7049) | 135 | Mar 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6998](https://github.com/chromiumembedded/cef/tree/6998) | 134 | Feb 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6943](https://github.com/chromiumembedded/cef/tree/6943) | 133 | Jan 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6834](https://github.com/chromiumembedded/cef/tree/6834) | 132 | Nov 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6778](https://github.com/chromiumembedded/cef/tree/6778) | 131 | Oct 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6723](https://github.com/chromiumembedded/cef/tree/6723) | 130 | Sep 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6668](https://github.com/chromiumembedded/cef/tree/6668) | 129 | Aug 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6613](https://github.com/chromiumembedded/cef/tree/6613) | 128 | Jul 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6533](https://github.com/chromiumembedded/cef/tree/6533) | 127 | Jun 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6478](https://github.com/chromiumembedded/cef/tree/6478) | 126 | May 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6422](https://github.com/chromiumembedded/cef/tree/6422) | 125 | Apr 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6367](https://github.com/chromiumembedded/cef/tree/6367) | 124 | Mar 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6312](https://github.com/chromiumembedded/cef/tree/6312) | 123 | Feb 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6261](https://github.com/chromiumembedded/cef/tree/6261) | 122 | Jan 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6167](https://github.com/chromiumembedded/cef/tree/6167) | 121 | Dec 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6099](https://github.com/chromiumembedded/cef/tree/6099) | 120 | Nov 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [6045](https://github.com/chromiumembedded/cef/tree/6045) | 119 | Oct 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [5993](https://github.com/chromiumembedded/cef/tree/5993) | 118 | Sep 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.0+ build system w/ 13.3 base SDK (Xcode 14.3), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [5938](https://github.com/chromiumembedded/cef/tree/5938) | 117 | Aug 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.0+ build system w/ 13.3 base SDK (Xcode 14.3), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja |
| [5845](https://github.com/chromiumembedded/cef/tree/5845) | 116 | Jun 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 13.0+ build system w/ 13.3 base SDK (Xcode 14.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5790](https://github.com/chromiumembedded/cef/tree/5790) | 115 | May 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 13.0+ build system w/ 13.3 base SDK (Xcode 14.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5735](https://github.com/chromiumembedded/cef/tree/5735) | 114 | Apr 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0-14.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5672](https://github.com/chromiumembedded/cef/tree/5672) | 113 | Mar 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5615](https://github.com/chromiumembedded/cef/tree/5615) | 112 | Feb 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5563](https://github.com/chromiumembedded/cef/tree/5563) | 111 | Jan 2023 | Win 10+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5481](https://github.com/chromiumembedded/cef/tree/5481) | 110 | Dec 2022 | Win 10+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5414](https://github.com/chromiumembedded/cef/tree/5414) | 109 | Nov 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5359](https://github.com/chromiumembedded/cef/tree/5359) | 108 | Oct 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5304](https://github.com/chromiumembedded/cef/tree/5304) | 107 | Sep 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5249](https://github.com/chromiumembedded/cef/tree/5249) | 106 | Aug 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5195](https://github.com/chromiumembedded/cef/tree/5195) | 105 | Jul 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5112](https://github.com/chromiumembedded/cef/tree/5112) | 104 | Jun 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5060](https://github.com/chromiumembedded/cef/tree/5060) | 103 | May 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.11+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [5005](https://github.com/chromiumembedded/cef/tree/5005) | 102 | Apr 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.11+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4951](https://github.com/chromiumembedded/cef/tree/4951) | 101 | Mar 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 11.3+ build system w/ 12.1 base SDK (Xcode 13.2.1), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4896](https://github.com/chromiumembedded/cef/tree/4896) | 100 | Feb 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 11.3+ build system w/ 12.1 base SDK (Xcode 13.2.1), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4844](https://github.com/chromiumembedded/cef/tree/4844) | 99 | Jan 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-13.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4758](https://github.com/chromiumembedded/cef/tree/4758) | 98 | Dec 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-13.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4692](https://github.com/chromiumembedded/cef/tree/4692) | 97 | Nov 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-13.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4664](https://github.com/chromiumembedded/cef/tree/4664) | 96 | Oct 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-13.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4638](https://github.com/chromiumembedded/cef/tree/4638) | 95 | Sep 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4606](https://github.com/chromiumembedded/cef/tree/4606) | 94 | Aug 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4577](https://github.com/chromiumembedded/cef/tree/4577) | 93 | Jul 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja |
| [4515](https://github.com/chromiumembedded/cef/tree/4515) | 92 | Jun 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja |
| [4472](https://github.com/chromiumembedded/cef/tree/4472) | 91 | Apr 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja |
| [4430](https://github.com/chromiumembedded/cef/tree/4430) | 90 | Mar 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja |
| [4389](https://github.com/chromiumembedded/cef/tree/4389) | 89 | Feb 2021 | Win 7+ deployment, Win 10+ build system w/ VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja |
| [4324](https://github.com/chromiumembedded/cef/tree/4324) | 88 | Dec 2020 | Win 7+ deployment, Win 10+ build system w/ VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja |
| [4280](https://github.com/chromiumembedded/cef/tree/4280) | 87 | Oct 2020 | Win 7+ deployment, Win 10+ build system w/ VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.10+ deployment, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja |
| [4240](https://github.com/chromiumembedded/cef/tree/4240) | 86 | Sep 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.10-10.15, 10.10+ deployment target, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja |
| [4183](https://github.com/chromiumembedded/cef/tree/4183) | 85 | Jul 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.10-10.15, 10.10+ deployment target, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [4147](https://github.com/chromiumembedded/cef/tree/4147) | 84 | Jun 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.15, 10.10+ deployment target, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [4103](https://github.com/chromiumembedded/cef/tree/4103) | 83 | Apr 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.15, 10.10+ deployment target, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [4044](https://github.com/chromiumembedded/cef/tree/4044) | 81 | Mar 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3987](https://github.com/chromiumembedded/cef/tree/3987) | 80 | Feb 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3945](https://github.com/chromiumembedded/cef/tree/3945) | 79 | Nov 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3904](https://github.com/chromiumembedded/cef/tree/3904) | 78 | Oct 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3865](https://github.com/chromiumembedded/cef/tree/3865) | 77 | Sep 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3809](https://github.com/chromiumembedded/cef/tree/3809) | 76 | Jul 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3770](https://github.com/chromiumembedded/cef/tree/3770) | 75 | Jun 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3729](https://github.com/chromiumembedded/cef/tree/3729) | 74 (CEF 74, 3) | Mar 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3683](https://github.com/chromiumembedded/cef/tree/3683) | 73 (CEF 73, 3) | Feb 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.17134.0 or 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3626](https://github.com/chromiumembedded/cef/tree/3626) | 72 (CEF 3) | Dec 2018 | Win 7+, VS2017 15.7.1+, Win 10.0.17134.0 or 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3578](https://github.com/chromiumembedded/cef/tree/3578) | 71 (CEF 3) | Oct 2018 | Win 7+, VS2017 15.7.1+, Win10.0.17134.0 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3538](https://github.com/chromiumembedded/cef/tree/3538) | 70 (CEF 3) | Sep 2018 | Win 7+, VS2017 15.7.1+, Win10.0.17134.0 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3497](https://github.com/chromiumembedded/cef/tree/3497) | 69 (CEF 3) | Jul 2018 | Win 7+, VS2017 15.7.1+, Win10.0.17134.0 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3440](https://github.com/chromiumembedded/cef/tree/3440) | 68 (CEF 3) | Jun 2018 | Win 7+, VS2017 15.7.1+, Win10.0.17134.0 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3396](https://github.com/chromiumembedded/cef/tree/3396) | 67 (CEF 3) | Apr 2018 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3359](https://github.com/chromiumembedded/cef/tree/3359) | 66 (CEF 3) | Mar 2018 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3325](https://github.com/chromiumembedded/cef/tree/3325) | 65 (CEF 3) | Jan 2018 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3282](https://github.com/chromiumembedded/cef/tree/3282) | 64 (CEF 3) | Dec 2017 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3239](https://github.com/chromiumembedded/cef/tree/3239) | 63 (CEF 3) | Oct 2017 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3202](https://github.com/chromiumembedded/cef/tree/3202) | 62 (CEF 3) | Sep 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.10-10.12, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3163](https://github.com/chromiumembedded/cef/tree/3163) | 61 (CEF 3) | Jul 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 8.3+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3112](https://github.com/chromiumembedded/cef/tree/3112) | 60 (CEF 3) | Jun 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 8.3+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3071](https://github.com/chromiumembedded/cef/tree/3071) | 59 (CEF 3) | Apr 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 8.3+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja |
| [3029](https://github.com/chromiumembedded/cef/tree/3029) | 58 (CEF 3) | Mar 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 8.3+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2987](https://github.com/chromiumembedded/cef/tree/2987) | 57 (CEF 3) | Jan 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2924](https://github.com/chromiumembedded/cef/tree/2924) | 56 (CEF 3) | Nov 2016 | Win 7+, VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2883](https://github.com/chromiumembedded/cef/tree/2883) | 55 (CEF 3) | Oct 2016 | Win 7+, VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.12, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2840](https://github.com/chromiumembedded/cef/tree/2840) | 54 (CEF 3) | Aug 2016 | Win 7+, VS2015u2 or VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.12, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2785](https://github.com/chromiumembedded/cef/tree/2785) | 53 (CEF 3) | Jul 2016 | Win 7+, VS2015u2 or VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.11, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2743](https://github.com/chromiumembedded/cef/tree/2743) | 52 (CEF 3) | May 2016 | Win 7+, VS2015u2 or VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.11, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.1.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2704](https://github.com/chromiumembedded/cef/tree/2704) | 51 (CEF 3) | Apr 2016 | Win 7+, VS2015u2, Win10.0.10586 SDK, Ninja | macOS 10.9-10.11, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.1.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2623](https://github.com/chromiumembedded/cef/tree/2623) | 49 (CEF 3) | Jan 2016 | WinXP+, VS2013u4 or VS2015u1 (experimental), Win10 SDK, Ninja | macOS 10.6-10.11, 10.6+ deployment target, 10.7+ build system w/ 10.10+ base SDK (Xcode 7.1.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja |
| [2526](https://github.com/chromiumembedded/cef/tree/2526) | 47 (CEF 3) | Oct 2015 | WinXP+, VS2013u4 or VS2015u1 (experimental), Win8.1 SDK, Ninja | macOS 10.6-10.11, 10.6+ deployment target, 10.10 base SDK, Xcode 6.1, Ninja, 64-bit only | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [2454](https://github.com/chromiumembedded/cef/tree/2454) | 45 (CEF 3) | Jul 2015 | WinXP+, VS2013u4, Win8.1 SDK, Ninja | macOS 10.6-10.10, 10.6+ deployment target, 10.9 base SDK, Xcode 6.1, Ninja, 64-bit only | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [2357](https://github.com/chromiumembedded/cef/tree/2357) | 43 (CEF 3) | Apr 2015 | WinXP+, VS2013u4, Win8.1 SDK, Ninja | macOS 10.6-10.10, 10.6+ deployment target, 10.9 base SDK, Xcode 6.1, Ninja, 64-bit only | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [2272](https://github.com/chromiumembedded/cef/tree/2272) | 41 (CEF 3) | Jan 2015 | WinXP+, VS2013u4, Win8.1 SDK, Ninja | macOS 10.6-10.10, 10.6+ deployment target, 10.9 base SDK, Xcode 6.1, Ninja, 64-bit only | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [2171](https://github.com/chromiumembedded/cef/tree/2171) | 39 (CEF 3) | Oct 2014 | WinXP+, VS2013u4, Win8.1 SDK, Ninja | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [2062](https://github.com/chromiumembedded/cef/tree/2062) | 37 (CEF 3) | Aug 2014 | WinXP+, VS2013, Win8 SDK, Ninja | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [1916](https://github.com/chromiumembedded/cef/tree/1916) | 35 (CEF 3) | Apr 2014 | WinXP+, VS2013, Win8 SDK, Ninja | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [1750](https://github.com/chromiumembedded/cef/tree/1750) | 33 (CEF 3) | Jan 2014 | WinXP+, VS2010-2013, Win8 SDK, Ninja | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [1650](https://github.com/chromiumembedded/cef/tree/1650) | 31 (CEF 3) | Oct 2013 | WinXP+, VS2010-2012, Win8 SDK, Ninja (optional) | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja |
| [1547](https://github.com/chromiumembedded/cef/tree/1547) | 29 (CEF 3) | Jul 2013 | WinXP+, VS2010-2012, Win8 SDK, Ninja (optional) | macOS 10.6-10.8, 10.6+ SDK, Xcode 3.2.6-4.x, Ninja (optional) | Ubuntu 12.04+, Debian Squeeze+, Ninja |
| [1453](https://github.com/chromiumembedded/cef/tree/1453) | 27 (CEF 1, 3) | Apr 2013 | WinXP+, VS2010, Win8 SDK, Ninja (optional) | macOS 10.6-10.8, 10.6+ SDK, Xcode 3.2.6-4.x, Ninja (optional) | Ubuntu 12.04+, Debian Squeeze+, Ninja (optional) |
| [1364](https://github.com/chromiumembedded/cef/tree/1364) | 25 (CEF 1, 3) | Jan 2013 | WinXP+, VS2010, Win8 SDK, Ninja (optional) | macOS 10.6-10.8, Xcode 3.2.6-4.x, Ninja (optional) | Ubuntu 12.04+, Debian Squeeze+, Ninja (optional) |
| [1271](https://github.com/chromiumembedded/cef/tree/1271) | 23 (CEF 1, 3) | Oct 2012 | WinXP+, VS2010, Win7 SDK   | macOS 10.6-10.8, 10.6+ SDK, Xcode 3.2.6-4.x | Ubuntu 12.04+, Debian Squeeze+ |
| [1180](https://github.com/chromiumembedded/cef/tree/1180) | 21 (CEF 1, 3) | Aug 2012 | WinXP+, VS2010, Win7 SDK   | macOS 10.6-10.7, 10.5+ SDK, Xcode 3.2.6-4.x | Ubuntu 12.04+, Debian Squeeze+ |
| [1084](https://github.com/chromiumembedded/cef/tree/1084) | 19 (CEF 1) | Apr 2012 | WinXP+, VS2008, Win7 SDK   | macOS 10.6-10.7, 10.5+ SDK, Xcode 3.2.6-4.x | Ubuntu 10.04+, Debian Squeeze+ |
| [1025](https://github.com/chromiumembedded/cef/tree/1025) | 18 (CEF 1) | Feb 2012 | WinXP+, VS2008, Win7 SDK   | macOS 10.6-10.7, 10.5+ SDK, Xcode 3.2.6-4.x | Ubuntu 10.04+, Debian Squeeze+ |
| [963](https://github.com/chromiumembedded/cef/tree/963) | 17 (CEF 1) | Dec 2011 | WinXP+, VS2008, Win7 SDK   | macOS 10.6-10.7, 10.5+ SDK, Xcode 3.2.6 | Ubuntu 10.04+, Debian Squeeze+ |

The following URL should be used for downloading release versions of CEF where YYYY is the release branch number.

  * https://github.com/chromiumembedded/cef/tree/YYYY

Note that 1025 and older branches contain only CEF1 source code and that 1547 and newer branches contain only CEF3 source code.

# Building from Source

Building from source code is currently supported on Windows, macOS and Linux platforms. Use of the Automated Method described below is recommended. Building the current CEF/Chromium master branch for local development is described on the [Master Build Quick Start](master_build_quick_start.md) page. Building the current CEF/Chromium stable branch automatically for production use is described on the  [Automated Build Setup](automated_build_setup.md#linux-configuration) page. For other branches see the build requirements listed in the "Release Branches" section above and the "Build Notes" section below.

## Automated Method

CEF provides tools for automatically downloading, building and packaging Chromium and CEF source code. These tools are the recommended way of building CEF locally and can also be integrated with automated build systems as described on the [Automated Build Setup](automated_build_setup.md) page. See the [Master Build Quick Start](master_build_quick_start.md) page for an example of the recommended workflow for local development builds.

These steps apply to the Git workflow only. The Git workflow is recommended for all users and supports CEF3 master and newer CEF3 release branches (1750+).

1\. Download the [automate-git.py script](https://github.com/chromiumembedded/cef/blob/master/tools/automate/automate-git.py). Use the most recent master version of this script even when building release branches.

2\. On Linux: Chromium requires that certain packages be installed. You can install them by running the [install-build-deps.sh script](master_build_quick_start.md#linux-setup) or by [explicitly running](automated_build_setup.md#linux-configuration) the necessary installation commands.

3\. Run the automate-git.py script at whatever interval is appropriate (for each CEF commit, once per day, once per week, etc).

To build master:

```sh
python /path/to/automate/automate-git.py --download-dir=/path/to/download
```

To build a release branch:

```sh
python /path/to/automate/automate-git.py --download-dir=/path/to/download --branch=2785
```

By default the script will download depot\_tools, Chromium and CEF source code, run Debug and Release builds of CEF, and create a binary distribution package containing the build artifacts in the "/path/to/download/chromium/src/cef/binary\_distrib" directory. Future runs of the script will perform the minimum work necessary (unless otherwise configured using command-line flags). For example, if there are no pending CEF or Chromium updates the script will do nothing.

If you run the script and CEF or Chromium updates are pending the "/path/to/download/chromium/src/cef" directory will be removed and replaced with a clean copy from "/path/to/download/cef\_(branch)" (specify the `--no-update` command-line flag to disable updates). Make sure to back up any changes that you made in the "/path/to/download/chromium/src/cef" directory before re-running the script.

The same download directory can be used for building multiple CEF branches (just specify a different `--branch` command-line value). The existing "/path/to/download/chromium/src/out" directory will be moved to "/path/to/download/out\_(previousbranch)" so that the build output from the previous branch is not lost. When you switch back to a previous branch the out directory will be restored to its original location.

The script will create a 32-bit build on Windows by default. To create a 64-bit build on Windows, macOS or Linux specify the `--x64-build` command-line flag. 32-bit builds on macOS are [no longer supported](https://groups.google.com/a/chromium.org/d/msg/chromium-dev/sdsDCkq_zwo/yep65H8Eg3sJ) starting with 2272 branch so this flag is now required when building 2272+ on that platform.

If you receive Git errors when moving an existing checkout from one branch to another you can force a clean Chromium Git checkout (specify the  `--force-clean` command-line flag) and optionally a clean download of Chromium dependencies (specify the `--force-clean-deps` command-line flag). Any build output that currently exists in the "src/out" directory will be deleted. Re-downloading the Chromium dependencies can take approximately 30 minutes with a reasonably fast internet connection.

Add the `--help` command-line switch to output a complete list of supported command-line options.

## Manual Downloading

See the [Master Build Quick Start](master_build_quick_start.md) page for an example of the recommended developer workflow.

## Manual Building

See the [Master Build Quick Start](master_build_quick_start.md) page for an example of the recommended developer workflow.

## Manual Packaging

After building both Debug and Release configurations you can use the make\_distrib tool (.bat on Windows, .sh on macOS and Linux) to create a binary distribution.

```sh
cd /path/to/chromium/src/cef/tools
./make_distrib.sh --ninja-build
```

If the process succeeds a binary distribution package will be created in the /path/to/chromium/src/cef/binary\_distrib directory.

See the [make\_distrib.py](https://github.com/chromiumembedded/cef/blob/master/tools/make_distrib.py) script for additional usage options.

The resulting binary distribution can then be built using CMake and platform toolchains. See the README.txt file included with the binary distribution for more information.

## Build Notes

This section summarizes build-related requirements and options.

  * Building on most platforms will require at least 8GB of system memory.
  * [Ninja](https://ninja-build.org/) must be used when building newer CEF/Chromium branches.
  * [Clang](https://clang.llvm.org/) is used by default for compiling/linking Chromium/CEF on macOS in all branches, Linux starting in 2063 branch, and Windows starting in 3282 branch.
  * [GYP](https://gyp.gsrc.io/docs/UserDocumentation.md) is supported by 2785 branch and older. [GN](http://www.chromium.org/developers/gn-build-configuration) is supported by 2785 branch and newer, and required starting with 2840 branch. Set `CEF_USE_GN=1` to build 2785 branch with GN instead of GYP.
  * To perform a 64-bit build on Windows (any branch) or macOS (branch 2171 or older) set `GYP_DEFINES=target_arch=x64` (GYP only) or build the `out/[Debug|Release]_GN_x64` target (GN only). To perform a 32-bit Linux build on a 64-bit Linux system see instructions on the [Automated Build Setup](automated_build_setup.md#linux-configuration) page.
  * To perform an "official" build set `GYP_DEFINES=buildtype=Official` (GYP only) or `GN_DEFINES=is_official_build=true` (GN only). This will disable debugging code and enable additional link-time optimizations in Release builds. See instructions on the [Automated Build Setup](automated_build_setup.md) page for additional official build recommendations.
  * Windows -
    * If multiple versions of Visual Studio are installed on your system you can set the GYP\_MSVS\_VERSION environment variable to create project files for that version. For example, set the value to "2015" for VS2015 or "2017" for VS2017. Check the Chromium documentation for the correct value when using other Visual Studio versions.
    * If you wish to use Visual Studio for debugging and compiling in combination with a Ninja build you can set `GYP_GENERATORS=ninja,msvs-ninja` (GYP only) or `GN_ARGUMENTS=--ide=vs2017 --sln=cef --filters=//cef/*` (GN only) to generate both Ninja and VS project files. Visual Studio is supported only for debugging and compiling individual source files -- it will not build whole targets successfully. You must use Ninja when building CEF/Chromium targets.
    * For best local developer (non-official debug) build-time performance:
        * When using VS2015 set `GN_DEFINES=is_win_fastlink=true` for improved compile and link time (branches <= 3202).
        * When using VS2017 or VS2019 set `GN_DEFINES=use_jumbo_build=true` for improved compile and link time (branches <= 4044).
        * Component builds are supported by 3202 branch and newer and significantly reduce link time. Add `is_component_build=true` to GN_DEFINES in combination with the above VS-version-specific values. Component builds cannot be used to create a CEF binary distribution. See [issue #1617](https://github.com/chromiumembedded/cef/issues/1617#issuecomment-1464996498) for details.
  * macOS -
    * The combination of deployment target and base SDK version will determine the platforms supported by the resulting binaries. For proper functioning you must use the versions specified under build requirements for each branch.
    * 32-bit builds are no longer supported with 2272 branch and newer. See [here](https://groups.google.com/a/chromium.org/d/msg/chromium-dev/sdsDCkq_zwo/yep65H8Eg3sJ) for the Chromium announcement.
  * Linux -
    * CEF is developed and tested on the Ubuntu version specified in the "Release Branches" section. It should be possible to build and run CEF on other compatible Linux distributions but this is untested.
    * The libgtkglext1-dev package is required in branch 1547 and newer to support the off-screen rendering example in cefclient. This is only a requirement for cefclient and not a requirement for other applications using CEF.

---

### Chromium Update (`docs/chromium_update.md`)

This page describes how to update CEF to use the newest Chromium revision.

**Contents**

- [Overview](#overview)
- [Recommended workflow](#recommended-workflow)
  - [1\. Setup a local developer checkout](#1-setup-a-local-developer-checkout)
  - [2\. Check for changes in Chromium's build requirements](#2-check-for-changes-in-chromiums-build-requirements)
  - [3\. Start the update](#3-start-the-update)
    - [A\. Identify the target Chromium version](#a-identify-the-target-chromium-version)
    - [B\. Run CEF's `patch_updater.py` script](#b-run-cefs-patch_updaterpy-script)
    - [C\. Identify potentially relevant Chromium changes](#c-identify-potentially-relevant-chromium-changes)
    - [D\. Identify problematic patterns in the Chromium source code](#d-identify-problematic-patterns-in-the-chromium-source-code)
  - [4\. Build CEF and fix whatever else is broken](#4-build-cef-and-fix-whatever-else-is-broken)
  - [5\. Run CEF tests](#5-run-cef-tests)
  - [6\. Update the compatible Chromium version](#6-update-the-compatible-chromium-version)
  - [7\. Create and submit a PR](#7-create-and-submit-a-pr)
  - [8\. Test your changes on other supported platforms](#8-test-your-changes-on-other-supported-platforms)
- [Resolving automate_git.py update failures](#resolving-automate_gitpy-update-failures)
- [Resolving Chromium breakage](#resolving-chromium-breakage)

---

# Overview

The Chromium developers work very hard to introduce new features and capabilities as quickly as possible. Consequently, projects like CEF that depend on Chromium must also be updated regularly. The update process can be complicated and must be done carefully to avoid introducing new bugs and breakage. Below are the steps to follow when updating CEF to work with a new Chromium revision.

# Recommended workflow

## 1\. Setup a local developer checkout

Setup a local developer checkout of the CEF/Chromium master branch as described on the [Master Build Quick Start](master_build_quick_start.md) page. The standard `automate-git.py` parameters discussed on that page are represented by the `[...]` placeholder in the below examples.

## 2\. Check for changes in Chromium's build requirements

Chromium's build requirements change over time. You may need to update your build environment before proceeding.

* **Windows**: Visual Studio and Windows SDK requirements are listed [here](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/windows_build_instructions.md#Setting-up-Windows) and [here](https://source.chromium.org/chromium/chromium/src/+/main:build/vs_toolchain.py;l=20;bpv=0). Visual Studio bootstrap installers for specific versions can be found [here](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-history#fixed-version-bootstrappers).
* **MacOS**: SDK and Xcode version requirements are listed [here](https://source.chromium.org/chromium/chromium/src/+/main:build/config/mac/mac_sdk.gni;l=43?q=mac_sdk_official_version&ss=chromium) and [here](https://source.chromium.org/chromium/chromium/src/+/main:build/mac_toolchain.py;l=44?q=MAC_BINARIES_LABEL&ss=chromium%2Fchromium%2Fsrc). SDK versions can also be mapped to Xcode versions using [this table](https://en.wikipedia.org/wiki/Xcode#Xcode_11.x_-_13.x_(since_SwiftUI_framework)).
* **Linux**: Version and distro requirements are listed [here](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md#System-requirements). Most dependency version issues can be avoided by building with a [sysroot image](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/sysroot.md) by setting `GN_DEFINES=use_sysroot=true`.

If the build requirements have changed the [MasterBuildQuickStart page](branches_and_building.md#development) will also need to be updated.

## 3\. Start the update

### A\. Identify the target Chromium version

The Chromium [release cycle](https://chromium.googlesource.com/chromium/src/+/master/docs/process/release_cycle.md) utilizes milestone versions (M98, M99, etc.) and [release channels](https://www.chromium.org/getting-involved/dev-channel/) (canary, beta, stable). New milestone versions branch approximately every 4 weeks and begin life in the canary channel. Over the next 4 weeks they progress through the beta and stable channels to reach Chrome's ~3 billion users globally.

The CEF project has a `master` branch for ongoing development and creates a [release branch](branches_and_building.md#release-branches) that tracks each milestone version. Automated builds are provided for [currently supported](branches_and_building.md#current-release-branches-supported) versions.

* **CEF master updates** target new milestone versions as they are announced to the chromium-dev mailing list. For example, [this email](https://groups.google.com/a/chromium.org/g/chromium-dev/c/uuVm_MltNY4/m/6GO-cpseAQAJ) was sent for the M100 branch. These versions should have 0 as the last component (e.g. "100.0.4896.0"). Updates are performed manually and usually take around 1 week to complete. The "Branch" date for upcoming milestones can be found on the [Chromium schedule](https://chromiumdash.appspot.com/schedule).
* **CEF beta and stable channel updates** use the version information published [here](https://chromiumdash.appspot.com/releases?platform=Windows). These versions should not have 0 as the last component (e.g. "99.0.4844.45"). Updates are performed automatically in most cases and a PR will be submitted to the public repository if the build succeeds.

To manually specify the Chromium version and update the checkout of master:

```sh
python automate-git.py [...] --no-build --fast-update --log-chromium-changes --chromium-checkout=refs/tags/100.0.4896.0
```

To manually specify the Chromium version and update the checkout of an existing release branch:

```sh
python automate-git.py [...] --no-build --fast-update --force-cef-update --branch=4844 --chromium-checkout=refs/tags/99.0.4844.45
```

### B\. Run CEF's `patch_updater.py` script

This will update the Chromium patch files in the `patch/patches` directory. If patch files cannot be updated automatically the `automate-git.py` script will fail.

Claude Code can assist with updating patches. See [tools/claude/README.md](https://github.com/chromiumembedded/cef/blob/master/tools/claude/).

**If one or more patch files have unresolved conflicts you will get a failure like the following:**

```
--------------------------------------------------------------------------------
!!!! FAILED PATCHES, fix manually and run with --resave
content_2015:
  Hunk #4 FAILED at 4220.
  1 out of 5 hunks FAILED -- saving rejects to file content/browser/frame_host/render_frame_host_impl.cc.rej
storage_partition_1973:
  Hunk #1 FAILED at 167.
  1 out of 1 hunk FAILED -- saving rejects to file content/browser/shared_worker/shared_worker_service_impl.cc.rej
--------------------------------------------------------------------------------
```

Use a text editor to manually fix the specified files, and then re-run the `patch_updater.py` script:

```sh
$ cd /path/to/chromium_git/chromium/src/cef/tools
$ python patch_updater.py
```

**If a patched file is missing (moved or deleted) you will get a failure like the following:**

```cpp
--> Reading patch file /path/to/chromium_git/chromium/src/cef/patch/patches/content_mojo_3123.patch
--> Skipping non-existing file /path/to/chromium_git/chromium/src/content/public/browser/document_service_base.h
--> Applying patch to /path/to/chromium_git/chromium/src
(Stripping trailing CRs from patch; use --binary to disable.)
can't find file to patch at input line 5
...
Skip this patch? [y] 
Skipping patch.
2 out of 2 hunks ignored
--> Saving changes to /path/to/chromium_git/chromium/src/cef/patch/patches/content_mojo_3123.patch
Traceback (most recent call last):
  File "/path/to/chromium_git/chromium/src/cef/tools/patch_updater.py", line 294, in <module>
    raise Exception('Failed to add paths: %s' % result['err'])
Exception: Failed to add paths: fatal: pathspec '/path/to/chromium_git/chromium/src/content/public/browser/document_service_base.h' did not match any files

```

You can use this Git command to discover what happened to the missing Chromium file:

```sh
$ cd /path/to/chromium_git/chromium/src
$ git log --full-history -1 -- content/public/browser/document_service_base.h
```

Once you know the offending Git commit hash you can use the `git show <hash>` command or load <https://crrev.com/>`<hash>` in a web browser to see the contents of the change. Edit the patch file manually in a text editor to fix the paths and then re-run the `patch_updater.py` script as shown above.

**To create a new patch file use this command:**

```sh
$ cd /path/to/chromium_git/chromium/src
$ git diff --no-prefix --relative [path1] [path2] > [name].patch
```

Copy the resulting `[name].patch` file to the `src/cef/patch/patches` directory and add an appropriate entry to the `src/cef/patch/patch.cfg` file.

**To add additional files to an existing patch file use this command:**

```sh
$ cd /path/to/chromium_git/chromium/src/cef/tools
$ python patch_updater.py --resave --patch [name] --add [path1] --add [path2]
```

All paths are relative to the `src` directory by default.

**After all patch files have been fixed you can re-run `automate-git.py` with the additional `--resave` command-line flag to resave the patch files and continue the update process:**

```sh
python automate-git.py [...] --resave
```

### C\. Identify potentially relevant Chromium changes

This step creates a `chromium_update_changes.diff` file in your download directory that will act as your guide when updating the CEF source code. CEF began life as a customized version of content\_shell and there's still a one-to-one relationship between many of the files. The list of relevant paths is taken from CEF's [CHROMIUM_UPDATE.txt](https://github.com/chromiumembedded/cef/blob/master/CHROMIUM_UPDATE.txt) file.

### D\. Identify problematic patterns in the Chromium source code

This step looks for patterns in Chromium src files that may cause issues for CEF. If these patterns are found then the `automate-git.py` script will create a `chromium_update_patterns.txt` file in your download directory and fail with output like the following:

```
Evaluating pattern: static_cast<StoragePartitionImpl\*>(
ERROR Matches found. See chromium_update_changes.diff for output.
```

In that case the contents of `chromium_update_patterns.txt` might look like this:

```text
!!!! WARNING: FOUND PATTERN: static_cast<StoragePartitionImpl\*>(
New instances in non-test files should be converted to call StoragePartition methods.
See storage_partition_1973.patch.

content/browser/loader/navigation_url_loader_impl.cc:1295:  auto* partition = static_cast<StoragePartitionImpl*>(storage_partition);
content/browser/renderer_interface_binders.cc:189:        static_cast<StoragePartitionImpl*>(host->GetStoragePartition())
```

Use the process described in part B to fix these failures.

## 4\. Build CEF and fix whatever else is broken

The diff file created in step C above will assist you in this process. Refer to the [Master Build Quick Start](master_build_quick_start.md) page for build instructions. If Chromium changes are required refer to the "Resolving Chromium breakage" section below.

Claude Code can assist with fixing compile/build errors. See [tools/claude/README.md](https://github.com/chromiumembedded/cef/blob/master/tools/claude/).

## 5\. Run CEF tests

After updating Chromium you should run some tests to verify that everything is working as expected. The tests should eventually be run on all supported platforms.

A\. The `cefclient` sample application supports various runtime modes that should be tested for startup/shutdown crashes or strange runtime behaviors (on MacOS use `open cefclient.app --args <args>`):

```sh
# Chrome bootstrap:
$ cefclient

# Chrome bootstrap + Alloy style:
$ cefclient --use-alloy-style
$ cefclient --use-alloy-style --use-native
$ cefclient --off-screen-rendering-enabled

# Multi-threaded message loop (Windows/Linux only):
$ cefclient --multi-threaded-message-loop
$ cefclient --use-alloy-style --multi-threaded-message-loop

# Chrome style + native parent (Windows/Linux only):
$ cefclient --use-native
```

B\. Run the various manual tests available via the Tests menu in `cefclient` to verify that everything still works. If any particular subsystem had significant changes (like printing, for example) then make sure to give that subsystem additional testing.

C\. Unit tests included in the `ceftests` application are expected to pass on all development platforms.

To run unit tests:
```sh
# Test Chrome style (default)
$ ceftests --use-views

# Test Alloy style
$ ceftests --use-views --use-alloy-style
```

On macOS use `./ceftests.app/Contents/MacOS/ceftests` as the test executable.

Some tests require synthetic events (mouse/key input, focus/activation, fullscreen, etc), device access, or timing considerations that are known to be flaky on headless/CI systems. To disable these tests during automated test runs add the `--gtest_filter=-[test:...]` command-line argument shown below.

On Windows:

```
:: Disabled tests:
:: - AudioOutputTest.*: Flaky
:: - DisplayTest.AutoResize: Flaky
:: - DisplayTest.Title: Flaky
:: - DraggableRegionsTest.*: Flaky
:: - NavigationTest.History: Flaky
:: - NavigationTest.Load*CtrlLeftClick*: Flaky
:: - NavigationTest.Load*MiddleClick*: Flaky
:: - PdfViewerTest.*: Flaky
:: - ScopedTempDir.TempDir: Flaky
:: - ViewsButtonTest.*Click*: Flaky
:: - ViewsButtonTest.MenuButtonCustomPopup*: Flaky
:: - ViewsTextfieldTest.TextfieldKeyEvent: Flaky
:: - ViewsWindowTest.WindowCreateWithOrigin: Flaky
ceftests --use-views [--use-alloy-style] ^
  --gtest_filter=-AudioOutputTest.*:DisplayTest.AutoResize:DisplayTest.Title:DraggableRegionsTest.*:NavigationTest.History:NavigationTest.Load*CtrlLeftClick*:NavigationTest.Load*MiddleClick*:PdfViewerTest.*:ScopedTempDir.TempDir:ViewsButtonTest.*Click*:ViewsButtonTest.MenuButtonCustomPopup*:ViewsTextfieldTest.TextfieldKeyEvent:ViewsWindowTest.WindowCreateWithOrigin
```

On macOS:

```sh
# Disabled tests:
# - DisplayTest.AutoResize: Flaky
# - ViewsButtonTest.MenuButtonCustomPopupActivate: Flaky
# - ViewsWindowTest.Window*Fullscreen*: Fails/crashes on headless agents
./ceftests.app/Contents/MacOS/ceftests --use-views [--use-alloy-style] \
  --gtest_filter=-DisplayTest.AutoResize:ViewsButtonTest.MenuButtonCustomPopupActivate:ViewsWindowTest.Window\*Fullscreen\*
```

On Linux:

```sh
# Headless agents often run using `xvfb-run`.
xvfb-run -a ceftests --use-views [--use-alloy-style] \

# Docker containers may not support the Chromium sandbox.
  --no-sandbox \

# Docker containers often default to 64MB for /dev/shm, which is far too small for Chromium.
# Run docker with `--shm-size=2g` or add `--disable-dev-shm-usage` to increase available space.
  --disable-dev-shm-usage \

# Disabled tests:
# - OSRTest.*: Flaky
# - ViewsWindowTest.WindowMaximize*: Flaky
# - ViewsWindowTest.WindowMinimize*: Flaky
  --gtest_filter=-OSRTest.*:ViewsWindowTest.WindowMaximize*:ViewsWindowTest.WindowMinimize*
```

If automated test runs are slow (tests timing out) you can additionally add `--test-timeout-multiplier=3` for e.g. 3x longer test timeouts.

## 6\. Update the compatible Chromium version

Update the compatible Chromium version listed in CEF's [CHROMIUM_BUILD_COMPATIBILITY.txt](https://github.com/chromiumembedded/cef/blob/master/CHROMIUM_BUILD_COMPATIBILITY.txt) file.

## 7\. Create and submit a PR

Create a commit with your changes and submit a PR as described on the [Contributing With Git](contributing_with_git.md) page. See the [CEF commit history](https://github.com/chromiumembedded/cef/commits/master) for examples of the expected commit message format.

## 8\. Test your changes on other supported platforms

You can update, build and run tests automatically on those platforms with the following command:

```sh
python automate-git.py [...] --run-tests --build-failure-limit=1000 --fast-update --force-cef-update
```

If running in headless mode on Linux install the `xvfb` package and add the `--test-prefix=xvfb-run --test-args="--no-sandbox"` command-line flags.

Access to automated builders as described on the [Automated Build Setup](automated_build_setup.md) page is recommended for this step.

# Resolving automate_git.py update failures

The automate_git.py script can sometimes fail to update an existing Chromium checkout due to errors while running Chromium tooling (git, gclient, etc). When that occurs you can perform the update steps manually.

The following example assumes the usual [file structure](master_build_quick_start.md#file-structure) with `path/to/chromium_git` as your existing automate_git.py download directory.

```sh
# Check out the required Chromium version.
$ cd path/to/chromium_git/chromium/src
$ git checkout refs/tags/100.0.4896.0

# Copy the `cef` directory to `chromium/src/cef` if it doesn't already exist.
$ cd path/to/chromium_git
$ cp -R cef chromium/src/

# Windows only. Apply the patch for `runhooks`.
$ cd path/to/chromium_git/chromium/src/cef/tools
$ python patch_updater.py --reapply --patch runhooks

# Windows only. Don't expect VS to be installed via depot_tools.
$ set DEPOT_TOOLS_WIN_TOOLCHAIN=0

# Update Chromium third_party dependencies and execute runhooks.
$ cd path/to/chromium_git/chromium/src
$ gclient sync --with_branch_heads
```

You can then run `cef_create_projects.[bat|sh]` and `ninja` to build CEF in the usual way.

# Resolving Chromium breakage

In most cases (say, 90% of the time) any code breakage will be due to naming changes, minor code reorganization and/or project name/location changes. The remaining 10% can require pretty significant changes to CEF, usually due to the ongoing refactoring in Chromium code. If you identify a change to Chromium that has broken a required feature for CEF, and you can't work around the breakage by making reasonable changes to CEF, then you should work with the Chromium team to resolve the problem.

1\. Identify the specific Chromium revision that broke the feature and make sure you understand why the change was made.

2\. Post a message to the chromium-dev mailing list explaining why the change broke CEF and either seeking additional information or suggesting a fix that works for both CEF and Chromium.

3\. After feedback from the Chromium developers create an issue in the [Chromium issue tracker](https://crbug.com) and a [code review](http://www.chromium.org/developers/contributing-code) with the fix and publish it with the appropriate (responsible) developer(s) as reviewers.

4\. Follow through with the Chromium developer(s) to get the code review committed.

The CEF build currently contains a patch capability that should be used only as a last resort or as a stop-gap measure if you expect the code review to take a while. The best course of action is always to get your Chromium changes accepted into the Chromium trunk if possible.

---

### Code Signing (`docs/code_signing.md`)

This page explains how to sign CEF-based applications for distribution on Windows and macOS, including macOS notarization.

**Contents**

- [Overview](#overview)
- [Windows](#windows)
  - [Prerequisites](#windows-prerequisites)
  - [Sign application binaries and installers](#sign-application-binaries-and-installers)
  - [Test with a self-signed certificate](#test-with-a-self-signed-certificate)
  - [Create a signed catalog](#create-a-signed-catalog)
- [macOS](#macos)
  - [Prerequisites](#macos-prerequisites)
  - [Choose entitlements](#choose-entitlements)
  - [Sign the application bundle](#sign-the-application-bundle)
  - [Notarize and staple](#notarize-and-staple)
  - [Disk images and installer packages](#disk-images-and-installer-packages)
- [Release validation and troubleshooting](#release-validation-and-troubleshooting)

---

# Overview

Code signing identifies the publisher and allows signature verification to detect changes to signed content. Signing is a release packaging step: finish compiling, stripping, combining architectures, editing resources and constructing the final layout before signing. Generate archive hashes and update metadata from the final signed artifacts.

Use your own signing identity and protect its private key. A signing service or hardware-backed key can perform signing without exposing the key to the build machine. Keep credentials outside the source tree and build logs, and verify the returned files before packaging them.

On Windows, executable files use Authenticode signatures; a signed catalog can also authenticate resource files. On macOS, nested code and the enclosing bundles are signed in order, with entitlements assigned to the appropriate executable processes. Distribution outside the Mac App Store additionally involves Apple's notarization service.

File lists and entitlements can change between Chromium versions. Check the sources corresponding to the Chromium revision used by your CEF build. The guidance below reflects the sources inspected as of October 2026; the Chromium links point to the main branch and may change over time.

# Windows

## Windows prerequisites

Install the Windows SDK and make `signtool.exe` available in your command prompt. Catalog creation also uses `makecat.exe`. [Obtain](https://learn.microsoft.com/en-us/windows/apps/package-and-deploy/code-signing-options) an Authenticode code-signing certificate and configure access to its private key through the certificate store, a hardware token, or a signing service.

The commands below run in **Command Prompt**, with an identity in the current user's Personal (`My`) certificate store. Replace `CERTIFICATE_THUMBPRINT` and `TIMESTAMP_URL` with your certificate's thumbprint and an RFC 3161 timestamp endpoint supported by your certificate provider. A machine-store identity additionally requires `/sm`; hardware or remote signing may require provider-specific configuration.

See Microsoft's [SignTool reference](https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool) for certificate selection and timestamp options. Chromium's [Windows updater signing script](https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/win/signing/sign.py) demonstrates signing embedded binaries before the enclosing installer. That script handles Chromium updater packaging and is a reference, rather than a general CEF application signing tool.

## Sign application binaries and installers

Inventory the executable binaries shipped with your application: the main executable, subprocess executables, application DLLs, CEF DLLs and any native dependencies. Sign unsigned binaries that you distribute under your identity. Preserve valid third-party signatures when your packaging and loading policy permit them.

For the CEF bootstrap configuration described in [Sandbox Setup](sandbox_setup.md#windows) and [Installer](installer.md), the bootstrap executable and its adjacent `chrome_elf.dll` must use the same signing certificate. Sign these with your application identity, along with the client DLL. A separately downloaded CEF shared installation retains its distribution certificate and catalog.

After all resource modifications, sign each binary:

```bat
signtool sign /s My /sha1 CERTIFICATE_THUMBPRINT /fd SHA256 /tr TIMESTAMP_URL /td SHA256 /v "MyApp.exe"
signtool sign /s My /sha1 CERTIFICATE_THUMBPRINT /fd SHA256 /tr TIMESTAMP_URL /td SHA256 /v "MyApp.dll"
signtool sign /s My /sha1 CERTIFICATE_THUMBPRINT /fd SHA256 /tr TIMESTAMP_URL /td SHA256 /v "chrome_elf.dll"
```

Here `/sha1` selects a certificate by thumbprint; `/fd SHA256` selects the signature digest. Verify each resulting file under the Authenticode policy:

```bat
signtool verify /pa /all /tw /v "MyApp.exe"
signtool verify /pa /all /tw /v "MyApp.dll"
signtool verify /pa /all /tw /v "chrome_elf.dll"
```

Treat failures and warnings as release failures, including a missing timestamp. Repeat for every shipped binary. Then build your installer from the signed payload, sign the resulting installer `.exe` or `.msi`, and verify it with the same commands. Signing the installer does not sign its contained binaries. ZIP and tar archives carry the already signed files.

## Test with a self-signed certificate

For local development, you can test bootstrap signing using a self-signed certificate. This certificate is trusted only on machines where you explicitly install it; use a publicly trusted code-signing certificate for release distribution.

Run the following in **PowerShell** under the account that will launch the application. It creates a test certificate and trusts it in that user's certificate stores:

```powershell
$certificate = New-SelfSignedCertificate -DnsName "cef-signing-test.invalid" `
  -Type CodeSigning -CertStoreLocation Cert:\CurrentUser\My
$certificatePath = Join-Path $env:TEMP "cef-signing-test.cer"
Export-Certificate -Cert $certificate -FilePath $certificatePath
Import-Certificate -FilePath $certificatePath -CertStoreLocation Cert:\CurrentUser\TrustedPublisher
Import-Certificate -FilePath $certificatePath -CertStoreLocation Cert:\CurrentUser\Root
```

Replace the application directory and filenames below with your staged bootstrap executable, client DLL and adjacent `chrome_elf.dll`. Sign each with the newly created certificate:

```powershell
$appDir = "C:\path\to\app"
foreach ($name in "MyApp.exe", "MyApp.dll", "chrome_elf.dll") {
  $path = Join-Path $appDir $name
  Set-AuthenticodeSignature -FilePath $path -Certificate $certificate -HashAlgorithm SHA256
  signtool verify /pa /all /v $path
  if ($LASTEXITCODE -ne 0) { throw "Signature verification failed: $path" }
}
```

This local test omits timestamping. The release signing commands above include a timestamp and check for its presence. Keeping the returned certificate object also avoids accidentally selecting another certificate from the Personal store.

After testing, open `certmgr.msc` and remove this test certificate from **Personal**, **Trusted Root Certification Authorities** and **Trusted Publishers**, identifying it by `$certificate.Thumbprint`. Remove the exported `.cer` file as well. Removing the trust entries makes these test signatures untrusted on the machine; rebuild or re-sign the test binaries before subsequent use.

## Create a signed catalog

A catalog contains hashes for an explicit set of files, including data files such as `.pak`, `.dat` and `.json` that do not have embedded Authenticode signatures. For CEF shared installations, read the [Windows Installer guide](installer.md), particularly [Sign your binaries](installer.md#3-sign-your-binaries), and the [bootstrap installer implementation and configuration](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md). Its download-time distribution verification checks the catalog and the expected certificate; creating a catalog alone does not configure an application to trust a new publisher. The implementation guide's [Extended Configuration](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md#extended-configuration) describes `certificate_thumbprint` for distributions signed with another identity, including the requirement for a distinct installation path and matching client-side load policy.

For a distribution you publish yourself, first stage the complete payload and sign its executable files. Then create a Catalog Definition File (`catalog.cdf`). This small example assumes `C:\staging` is the distribution root:

```ini
[CatalogHeader]
Name=catalog.cat
ResultDir=C:\staging
PublicVersion=0x00000200
EncodingType=0x00010001
CatalogVersion=2
HashAlgorithms=SHA256

[CatalogFiles]
<HASH>libcef=C:\staging\Release\libcef.dll
<HASH>resources=C:\staging\Resources\resources.pak
<HASH>icudtl=C:\staging\Resources\icudtl.dat
```

Generate one uniquely named entry for **every payload file**, using its actual staged path. The paths above are illustrative. Exclude the catalog itself and the temporary CDF. End the CDF with a newline. [MakeCat](https://learn.microsoft.com/en-us/windows/win32/seccrypto/using-makecat) computes catalog hashes from these files; do not substitute ordinary SHA-256 checksums for its file-hashing procedure.

```bat
makecat -v "C:\staging\catalog.cdf"
signtool sign /s My /sha1 CERTIFICATE_THUMBPRINT /fd SHA256 /tr TIMESTAMP_URL /td SHA256 /v "C:\staging\catalog.cat"
signtool verify /pa /all /tw /v "C:\staging\catalog.cat"
signtool verify /pa /v /c "C:\staging\catalog.cat" "C:\staging\Release\libcef.dll"
signtool verify /pa /v /c "C:\staging\catalog.cat" "C:\staging\Resources\resources.pak"
```

Verify every member against the signed catalog. Package the signed payload and `catalog.cat` together after removing the temporary CDF. If payload content changes, regenerate and re-sign the catalog. For an existing CEF shared distribution, preserve its files and catalog and follow the installer's configured certificate verification policy.

# macOS

## macOS prerequisites

Use a macOS signing machine with Xcode installed and selected through `xcode-select`. [Obtain](https://developer.apple.com/help/account/certificates/create-developer-id-certificates/) a **Developer ID Application** certificate through the Apple Developer Program for distribution outside the Mac App Store. Import it and its private key into a keychain accessible to the signing user, and confirm the identity:

```sh
security find-identity -v -p codesigning
```

For an unattended build, [configure](https://developer.apple.com/forums/thread/712005) the signing keychain's unlock and private-key access before invoking `codesign`. If you change the user's keychain search list, save and restore it after signing. Lock a dedicated signing keychain when finished. Keep keychain passwords in your build system's secret store.

Use a Release, non-component CEF distribution. Assemble the final `.app` with its framework, resources and helper apps before signing. Preserve framework symlinks when copying it. The supplied CMake configuration constructs a versioned framework for newer Xcode versions; see the binary distribution's `README.txt` and [CEF framework copy macro](https://github.com/chromiumembedded/cef/blob/master/cmake/cef_macros.cmake.in).

Chromium's [macOS signing documentation](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/signing/README.md), [component definitions](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/signing/parts.py) and [signing implementation](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/signing/signing.py) provide reference behavior. [sign_chrome.py](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/sign_chrome.py) expects Chrome's bundle layout and configuration, so a CEF application's packaging script must supply its own component paths.

## Choose entitlements

Enable the Hardened Runtime when signing executable processes. Start with the entitlement files from the matching Chromium revision and adapt them to your application's features:

| Component | Chromium reference | Application guidance |
| --- | --- | --- |
| Main application | [app-entitlements.plist](https://chromium.googlesource.com/chromium/src/+/main/chrome/app/app-entitlements.plist) | Start with this file from the matching Chromium revision. Review capability changes against the features your application supports. |
| Renderer helper | [helper-renderer-entitlements.plist](https://chromium.googlesource.com/chromium/src/+/main/chrome/app/helper-renderer-entitlements.plist) | As of October 2026, Chromium enables `com.apple.security.cs.allow-jit` for V8. |
| GPU helper | [helper-gpu-entitlements.plist](https://chromium.googlesource.com/chromium/src/+/main/chrome/app/helper-gpu-entitlements.plist) | As of October 2026, Chromium also enables `com.apple.security.cs.allow-jit` here. Check the matching revision. |
| Generic, Alerts and Plugin helpers | [parts.py](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/signing/parts.py) | Review each role. The example below assigns an empty entitlement dictionary to these helpers; older releases or custom helper roles may need different settings. |
| Framework and dylibs | [parts.py](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/signing/parts.py) | Process entitlements belong on executables, rather than on their loaded libraries. |

Use the unbranded `app-entitlements.plist` listed above. Chromium also has an `app-entitlements-chrome.plist` for Google Chrome, but its identity-specific entitlements are tied to Google's signing identity and should not be copied into a CEF application. Chromium's development signing mode adds `com.apple.security.get-task-allow` to permit debugging; omit that entitlement from release signatures. See the [Chromium signing documentation](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/signing/README.md) for these distinctions.

For the example below, prepare `app-entitlements.plist`, `renderer-entitlements.plist`, `gpu-entitlements.plist` and `helper-entitlements.plist` beside your signing script. Copy Chromium's `app-entitlements.plist` from the matching revision for the main application. As of October 2026, it enables audio input, Bluetooth, camera, printing, USB, location and photo-library access. Review these capabilities against your application's supported features before changing them. Capability entitlements do not replace required `Info.plist` usage descriptions or user consent.

The renderer and GPU files can start with this dictionary:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>com.apple.security.cs.allow-jit</key>
  <true/>
</dict>
</plist>
```

For the generic helper's empty entitlement file, replace the dictionary with `<dict/>`. Keep the main application's separate `app-entitlements.plist` prepared above. If a custom subprocess executable serves multiple roles, its entitlements must cover the roles it actually executes. Entitlements on the outer application do not grant those capabilities to separate helper processes.

Chromium's renderer and GPU entitlement files provide a starting point, rather than a promise of compatibility with every CEF version. Avoid adding `allow-unsigned-executable-memory`, `disable-executable-page-protection` or `disable-library-validation` indiscriminately. Investigate a demonstrated requirement before granting an exception.

## Sign the application bundle

Sign from the inside out: nested libraries and executables, their containing bundles, then the outer application. Explicitly sign Mach-O libraries in the CEF framework's `Libraries` directory. Avoid `--deep` for signing: it does not reliably discover code in nonstandard locations and cannot assign the correct entitlements to each process. See Apple's [code signing guidance](https://developer.apple.com/library/archive/technotes/tn2206/_index.html).

Signing an `.app` bundle also signs its main executable, identified by `CFBundleExecutable` in `Contents/Info.plist` and located in `Contents/MacOS`. You do not need a separate signing command for that binary. This applies to both the main application and each helper app. Additional executables inside a bundle must be signed explicitly before signing the enclosing bundle.

This **Bash** example handles the usual CEF sample layout. Replace `MyApp` and the signing identity; run it from the directory containing your entitlement files. The helper names must match the names and process roles produced by your build.

```
/* Detailed source-code truncated for AI context efficiency. */
```

The loop skips helpers absent from the selected CEF release. Confirm that every helper your build requires is present; the loop is not a bundle-completeness check. Extend the signing inventory for additional frameworks, crash handlers, launchers, native modules or other embedded code. Sign these before their containing bundle. For a standalone executable, use `--options runtime` to enable the Hardened Runtime and pass `--entitlements` if the process needs additional capabilities. For example, an executable that uses V8's JIT needs the `com.apple.security.cs.allow-jit` entitlement; a launcher that does not need additional capabilities can omit the entitlement file. Dylibs and native library modules do not need these process-specific options or entitlements. Traverse actual files once rather than signing both a framework symlink and its target. A framework with multiple versions needs each version signed separately.

Use `--keychain /path/to/signing.keychain-db` on signing commands if the identity resides in a dedicated keychain. Inspect the main application and each helper to confirm the identity, runtime flags and entitlements:

```sh
codesign --display --verbose=4 "/path/to/MyApp.app"
codesign --display --entitlements :- "/path/to/MyApp.app/Contents/Frameworks/MyApp Helper (Renderer).app"
```

## Notarize and staple

Use `notarytool` for notarization. Apple's [notarization overview](https://developer.apple.com/documentation/security/notarizing-macos-software-before-distribution) and [custom workflow guide](https://developer.apple.com/documentation/security/customizing-the-notarization-workflow) describe authentication, submission and ticket attachment.

Store credentials in a keychain profile. This command prompts for your Apple Account, team and app-specific password; an App Store Connect API key is another supported authentication method:

```sh
xcrun notarytool store-credentials "myapp-notary"
```

Submit an archive of the signed app, and record the returned submission ID:

```sh
ditto -c -k --sequesterRsrc --keepParent "/path/to/MyApp.app" "/path/to/MyApp-notarization.zip"
xcrun notarytool submit "/path/to/MyApp-notarization.zip" \
  --keychain-profile "myapp-notary" --wait --output-format json
```

Require status **Accepted** before proceeding. Retrieve the log if rejected or if you need to investigate warnings:

```sh
xcrun notarytool log SUBMISSION_ID --keychain-profile "myapp-notary" notarization-log.json
```

Staple the ticket to the submitted app, validate it, and assess Gatekeeper acceptance:

```sh
xcrun stapler staple "/path/to/MyApp.app"
xcrun stapler validate "/path/to/MyApp.app"
codesign --verify --deep --strict --verbose=2 "/path/to/MyApp.app"
spctl --assess --type execute --verbose=2 "/path/to/MyApp.app"
```

ZIP files cannot be stapled. For ZIP distribution, create a **new** archive from the stapled app and distribute that archive. Preserve symlinks and bundle metadata. A timeout while waiting does not necessarily mean rejection; query the existing submission with `notarytool info SUBMISSION_ID` before resubmitting.

## Disk images and installer packages

For a DMG, put the signed and stapled app into the final image, then sign the image with your Developer ID Application identity:

```sh
codesign --force --sign "Developer ID Application: Example Company (TEAMID)" \
  --timestamp "/path/to/MyApp.dmg"
```

Submit the DMG with `notarytool submit`, require acceptance, then run `stapler staple` and `stapler validate` on the DMG. Creating or signing a DMG does not replace signing the enclosed application.

A flat `.pkg` uses a separate **Developer ID Installer** identity. Build it from the signed app, then sign it with `productsign`:

```sh
productsign --sign "Developer ID Installer: Example Company (TEAMID)" \
  "/path/to/MyApp-unsigned.pkg" "/path/to/MyApp.pkg"
pkgutil --check-signature "/path/to/MyApp.pkg"
```

Submit and staple the signed package using the same notarization workflow, then check it with `spctl --assess --type install --verbose=2`. Chromium's [signing documentation](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mac/signing/README.md#the-installer-identity) explains the separate installer identity, and Apple's [code signing guide](https://developer.apple.com/library/archive/technotes/tn2206/_index.html) covers framework and container signing.

# Release validation and troubleshooting

Test the final downloaded artifact on a clean system, including installation, first launch, renderer startup, GPU rendering, enabled media features, normal exit and relaunch. Exercise every architecture you distribute. A valid signature does not by itself prove the application works.

On Windows, verify each embedded signature, the installer and any catalog members. Check that the bootstrap and adjacent `chrome_elf.dll` use the same certificate, and that shared-install catalog verification uses the expected distribution certificate. A successful signature check does not guarantee the absence of SmartScreen reputation warnings.

On macOS, verify the extracted or installed app as well as its shipping container. Test launch through Finder after a real browser download so quarantine and Gatekeeper behavior are exercised. Check a stapled app on a machine without network access when offline launch is required.

If macOS reports unsigned code or an invalid sealed resource, inspect the specific path in the verification output or notarization log. Check framework libraries and executable code in resource directories, finish all bundle changes before signing, and repeat signing from the affected inner component outward. For helper crashes, inspect that helper's own entitlements and the system crash report. See Apple's [common notarization issues](https://developer.apple.com/documentation/security/resolving-common-notarization-issues).

The Hardened Runtime's library validation can reject libraries signed by another team. Prefer signing your application and its bundled libraries with the same Team ID. For library-validation failures, check the loaded libraries' signatures and Team IDs before adding a `disable-library-validation` exception.

Automated signing should stop on verification failure. Retry temporary timestamp-service errors with a bounded delay, while preserving certificate, signature and notarization errors for investigation. Publish only after signature, catalog or notarization checks and application smoke tests succeed.

---

### Contributing With Git (`docs/contributing_with_git.md`)

This page provides information about using Git to contribute code changes to CEF.

**Contents**

- [Overview](#overview)
- [Initial Setup](#initial-setup)
- [Working With Private Changes](#working-with-private-changes)
  - [Creating a Branch](#creating-a-branch)
  - [Creating a Commit](#creating-a-commit)
  - [Modifying a Commit](#modifying-a-commit)
  - [Rebasing on Upstream Changes](#rebasing-on-upstream-changes)
  - [Deleting a Branch](#deleting-a-branch)
  - [Cleaning a Checkout](#cleaning-a-checkout)
- [Working With Pull Requests](#working-with-pull-requests)
  - [Coding Style](#coding-style)
  - [Creating a Pull Request](#creating-a-pull-request)
  - [Reviewing a Pull Request](#reviewing-a-pull-request)

---

# Overview

The CEF project uses the Git source code management system hosted via GitHub. The easiest way to contribute changes to CEF is by creating your own personal fork of the CEF Git repository and submitting pull requests with your proposed modifications. This document is intended as a quick-start guide for developers who already have some familiarity with Git. If you are completely new to Git you might want to review the series of [Git tutorials](https://docs.github.com/en/get-started/getting-started-with-git) provided by GitHub.

# Initial Setup

Git can maintain your changes both locally and on a remote server. To work with Git efficiently the remote server locations must be configured properly.

1\. Log into GitHub and create a public forked version of the cef.git repository using the Fork button at <https://github.com/chromiumembedded/cef>. This public linked fork will be used to create and submit pull requests.

2\. Optionally, create a private unlinked fork using git commands directly. This private fork can be used for day-to-day development without exposing your work publicly.

3\. Check out CEF/Chromium source code as described on the [Master Build Quick Start](master_build_quick_start.md) or [Branches And Building](branches_and_building.md) page. Note that if you use the automate-git.py tool you will want to back up your customized CEF checkout before changing branches or performing a clean build.

4\. Change the remote origin of the CEF checkout so that it points to your private forked repository. This is the remote server location that the `git push` and `git pull` commands will operate on by default.

```sh
cd /path/to/chromium/src/cef

# Replace <UserName> with your GitHub user name.
# If you don't have a private fork, point origin to your public fork instead.
git remote set-url origin https://<UserName>@github.com/<UserName>/cef_private.git
```

5\. Add the remote public location pointing to your public forked repository. This is used to push branches for pull request submission.

```sh
# Replace <UserName> with your GitHub user name.
git remote add public https://<UserName>@github.com/<UserName>/cef.git
```

6\. Set the remote upstream of the CEF checkout so that you can merge changes from the main CEF repository.

```sh
git remote add upstream https://github.com/chromiumembedded/cef.git
```

7\. Verify that the remotes are configured correctly.

```sh
git remote -v
```

You should see output like the following:

```cpp
origin    https://<UserName>@github.com/<UserName>/cef_private.git (fetch)
origin    https://<UserName>@github.com/<UserName>/cef_private.git (push)
public    https://<UserName>@github.com/<UserName>/cef.git (fetch)
public    https://<UserName>@github.com/<UserName>/cef.git (push)
upstream    https://github.com/chromiumembedded/cef.git (fetch)
upstream    https://github.com/chromiumembedded/cef.git (push)
```

8\. Configure your name and email address.

```sh
git config user.name "User Name"
git config user.email user@example.com
```

9\. Configure the correct handling of line endings in the repository.

```sh
# Use this value on all platforms. Files will be unchanged in the working
# directory and converted to LF line endings in the object database.
git config core.autocrlf input

# Cause Git to abort actions on files with mixed line endings if the change is
# not reversible (e.g. changes to binary files that are accidentally classified
# as text).
git config core.safecrlf true
```

# Working With Private Changes

You can now commit changes to your personal repository and merge upstream changes from the main CEF repository. To facilitate creation of a pull request or the sharing of your code changes with other developers you should make your changes in a branch. Use `git push origin` to push changes to your private fork for day-to-day development, and `git push public` when you're ready to submit a pull request.

## Creating a Branch

Create a new personal branch for your changes.

```sh
# Start with the branch that your changes will be based upon.
git checkout master

# Create a new personal branch for your changes.
# Replace <BranchName> with your new branch name.
git checkout -b <BranchName>
```

## Creating a Commit

After making local modifications you can commit them to your personal branch.

```sh
# For example, add a specified file by path.
git add path/to/file.txt

# For example, add all existing files that have been modified or deleted.
git add -u

# Commit the modifications locally.
git commit -m "A good description of the fix (issue #1234)"

# Push the modifications to your personal remote repository.
git push origin <BranchName>
```

## Modifying a Commit

You can also modify an existing commit if you need to make additional changes.

```sh
# For example, add all existing files that have been modified or deleted.
git add -u

# Update the current HEAD commit with the changes.
git commit --amend

# Push the modifications to your personal remote repository.
# Using the `--force` argument is not recommended if multiple people are sharing the
# same branch.
git push origin <BranchName> --force
```

## Rebasing on Upstream Changes

The main CEF repository will receive additional commits over time. You will want to include these changes in your personal repository. To keep Git history correct (showing upstream CEF commits on the CEF branch instead of on your personal branch) you will need to rebase the local CEF branch before rebasing your local personal branch.

```sh
# Fetch changes from the main CEF repository. This does not apply them to any
# particular branch.
git fetch upstream

# Check out the local CEF branch that tracks the upstream CEF branch.
# Replace "master" with a different branch name as appropriate (e.g. "2171", "2272", etc).
git checkout master

# Rebase your local CEF branch on top of the upstream CEF branch.
# After this command your local CEF branch should be identical to the upstream CEF branch.
git rebase upstream/master

# Check out the personal branch that you want to update with changes from the CEF branch.
# Replace <BranchName> with the name of your branch.
git checkout <BranchName>

# Rebase your personal branch on top of the local CEF branch.
# After this command your local commits will come after all CEF commits on the same branch.
git rebase master

# Push the modifications to your personal remote repository.
git push origin <BranchName>
```

You may get merge conflicts if your personal changes conflict with changes made to the main CEF respository. For instructions on resolving merge conflicts see [this articicle](https://help.github.com/articles/resolving-merge-conflicts-after-a-git-rebase/).

For more information on using the rebase command go [here](https://www.atlassian.com/git/tutorials/merging-vs-rebasing).

## Deleting a Branch

Once you no longer need a branch you can delete it both locally and remotely. Do not delete branches that are associated with open pull requests.

```sh
# Delete the branch locally.
git branch -D <BranchName>

# Delete the branch remotely.
git push origin --delete <BranchName>
```

## Cleaning a Checkout

You can remove all local changes from your checkout using the below commands.

```sh
# Check the current state of the repository before deleting anything.
git status

# Remove all non-committed files and directories from the local checkout.
# If you run this command with JCEF it will also remove all third_party directories and you will
# need to re-run the `gclient runhooks` command.
git clean -dffx

# Remove all local commits from the current branch and reset branch state to match
# origin/master. Replace "origin/master" with a different remote branch name as appropriate.
git reset --hard origin/master
```

# Working With Pull Requests

Once your personal changes are complete you can request that they be merged into the main CEF (or JCEF) repository. This is done using a pull request. Before submitting a pull request you should:

* Rebase your changes on the upstream CEF (or JCEF) branch (see "Rebasing on Upstream Changes").
* Fix any coding style issues (see "Coding Style").
* Make sure your changes follow [API versioning guidelines](api_versioning.md#usage-in-pull-requests).
* Find or create an appropriate issue in the [CEF issue tracker](https://github.com/chromiumembedded/cef/issues) (or [JCEF issue tracker](https://github.com/chromiumembedded/java-cef/issues) if the change targets that project). Make sure the issue number is referenced in your commit description.
* Include new or modified unit tests as appropriate to the functionality.
* Remove unnecessary or unrelated changes.

## Coding Style

CEF uses the [Chromium coding style](https://chromium.googlesource.com/chromium/src/+/master/styleguide/styleguide.md). All C/C++, ObjC, Java and Python code must be formatted using the fix_style tool. For example, to fix the style of the unstaged files in your CEF Git checkout:

```sh
cd /path/to/chromium/src/cef
./tools/fix_style.sh unstaged
```

The fix_style tool supports file paths and git hashes as input. Run `tools/fix_style.[bat|sh]` without arguments for complete usage information.

Changes to other types of files should match the existing style in that file.

## Creating a Pull Request

Pull requests can only be created from a public repository that was [forked](https://docs.github.com/articles/fork-a-repo) using the GitHub interface. Push your branch to your public fork and then create the pull request as described [here](https://docs.github.com/articles/creating-a-pull-request-from-a-fork). Pull requests will only be accepted if they meet the requirements described above.

```sh
# Push your branch to your public fork for PR submission.
git push public <BranchName>
```

## Reviewing a Pull Request

Your pull request will be reviewed by one or more CEF developers. Please address any comments and update your pull request. The easiest way to update a pull request is by pushing new commits to the same branch -- those new commits will be automatically reflected in the pull request. Once your changes are deemed acceptable they will be squashed and merged into the main CEF repository.

The contents of a pull request can also be downloaded as a patch file and applied to your local Git checkout:

```sh
# Download the patch file (replace {pull_no} with the PR number).
curl -L https://github.com/chromiumembedded/cef/pull/{pull_no}.diff -o name.patch

# Apply the patch file to your local Git checkout.
git apply name.patch
```

---

### Crash Reporting (`docs/crash_reporting.md`)

This page explains how to handle crashes in CEF-based applications.

**Contents**

- [Overview](#overview)
- [Configuration](#configuration)
  - [[Config] section](#config-section)
  - [[CrashKeys] section](#crashkeys-section)
- [Testing](#testing)
- [Decoding Minidumps](#decoding-minidumps)

---

# Overview

As a developer or vendor that cares about software quality you would like to know when and how your application is crashing in the wild. A crash reporting system is an important part of that feedback loop. Applications using CEF version 3.2883.1543 or newer have the option to save crash reports locally or upload them to a web server for later analysis. CEF generates minidump files that include exception state, callstacks, stack memory, and loaded modules. The crash report upload, if enabled, includes the minidump file and configurable crash metadata information such as product state, command-line flags and crash keys. Minidump files can be analyzed using existing systems such as [Socorro](https://wiki.mozilla.org/Socorro) or command-line tools (see the "Decoding Minidumps" section).

CEF provides a simple HTTP server script written in Python that can be used for testing crash report upload (see the Testing section below). See the Socorro documentation for details on how to build a robust crash reporting server for use with production applications.

The crash reporting capability in CEF/Chromium is implemented using [Crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/master/README.md) on Windows and macOS, and [Breakpad](https://chromium.googlesource.com/breakpad/breakpad) on Linux.

# Configuration

Crash reporting is configured using an INI-style config file named "crash_reporter.cfg". On Windows and Linux this file must be placed next to the main application executable. On macOS this file must be placed in the top-level app bundle Resources directory (e.g. "<appname>.app/Contents/Resources"). See comments in [include/cef_crash_util.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_crash_util.h) for the most up-to-date version of this documentation.

The "crash_reporter.cfg" file contents are defined as follows:

```sh
# Comments start with a hash character and must be on their own line.

[Config]
ProductName=<Value of the "prod" crash key; defaults to "cef">
ProductVersion=<Value of the "ver" crash key; defaults to the CEF version>
AppName=<Windows only; App-specific folder name component for storing crash
         information; default to "CEF">
ExternalHandler=<Windows only; Name of the external handler exe to use
                 instead of re-launching the main exe; default to empty>
BrowserCrashForwardingEnabled=<macOS only; True if browser process crashes
                              should be forwarded to the system crash
                              reporter; default to false>
ServerURL=<crash server URL; default to empty>
RateLimitEnabled=<True if uploads should be rate limited; default to true>
MaxUploadsPerDay=<Max uploads per 24 hours, used if rate limit is enabled;
                  default to 5>
MaxDatabaseSizeInMb=<Total crash report disk usage greater than this value
                     will cause older reports to be deleted; default to 20>
MaxDatabaseAgeInDays=<Crash reports older than this value will be deleted;
                      default to 5>

[CrashKeys]
my_key1=<small|medium|large>
my_key2=<small|medium|large>
```

## [Config] section

Values in the "[Config]" section work as follows:

* If "ProductName" and/or "ProductVersion" are set then the specified values will be included in the crash dump metadata. On macOS if these values are set to empty then they will be retrieved from the Info.plist file using the "CFBundleName" and "CFBundleShortVersionString" keys respectively.
* If "AppName" is set on Windows then crash report information (metrics, database and dumps) will be stored locally on disk under the "C:\Users\\[CurrentUser]\AppData\Local\\[AppName]\User Data" folder. On other platforms the CefSettings.user_data_path value will be used.
* If "ExternalHandler" is set on Windows then the specified exe will be launched as the crashpad-handler instead of re-launching the main process exe. The value can be an absolute path or a path relative to the main exe directory. On Linux the CefSettings.browser_subprocess_path value will be used. On macOS the existing subprocess app bundle will be used.
* If "BrowserCrashForwardingEnabled" is set to true on macOS then browser process crashes will be forwarded to the system crash reporter. This results in the crash UI dialog being displayed to the user and crash reports being logged under "~/Library/Logs/DiagnosticReports". Forwarding of crash reports from non-browser processes and Debug builds is always disabled.
* If "ServerURL" is set then crashes will be uploaded as a multi-part POST request to the specified URL. Otherwise, reports will only be stored locally on disk.
* If "RateLimitEnabled" is set to true then crash report uploads will be rate limited as follows:
    * If "MaxUploadsPerDay" is set to a positive value then at most the specified number of crashes will be uploaded in each 24 hour period.
    * If crash upload fails due to a network or server error then an incremental backoff delay up to a maximum of 24 hours will be applied for retries.
    * If a backoff delay is applied and "MaxUploadsPerDay" is > 1 then the "MaxUploadsPerDay" value will be reduced to 1 until the client is restarted. This helps to avoid an upload flood when the network or server error is resolved.
    * Rate limiting is not supported on Linux.
* If "MaxDatabaseSizeInMb" is set to a positive value then crash report storage on disk will be limited to that size in megabytes. For example, on Windows each dump is about 600KB so a "MaxDatabaseSizeInMb" value of 20 equates to about 34 crash reports stored on disk. Not supported on Linux.
* If "MaxDatabaseAgeInDays" is set to a positive value then crash reports older than the specified age in days will be deleted. Not supported on Linux.

## [CrashKeys] section

A maximum of 26 crash keys of each size can be specified for use by the application. Crash key values will be truncated based on the specified size (small = 64 bytes, medium = 256 bytes, large = 1024 bytes). The value of crash keys can be set from any thread or process using the CefSetCrashKeyValue function. These key/value pairs will be sent to the crash server along with the crash dump file.

# Testing

CEF provides a [tools/crash_server.py](https://github.com/chromiumembedded/cef/blob/master/tools/crash_server.py) script that implements a simple HTTP server for receiving crash report uploads from a Breakpad/Crashpad client (any application using CEF version 3.2883.1543 or newer). This script is intended for testing purposes only. An HTTPS server and a system such as [Socorro](https://wiki.mozilla.org/Socorro) should be used when uploading crash reports from production applications. See comments in the crash_server.py script for the most up-to-date version of this documentation.

Usage of the crash_server.py script is as follows:

1\. Run the script from the command-line. The first argument is the server port number and the second argument is the directory where uploaded report information will be saved:

```sh
python crash_server.py 8080 /path/to/dumps
```

2\. Create a "crash_reporter.cfg" file at the required platform-specific location. On Windows and Linux this file must be placed next to the main application executable. On macOS this file must be placed in the top-level app bundle Resources directory (e.g. "<appname>.app/Contents/Resources"). At a minimum it must contain a "ServerURL=http://localhost:8080" line under the "[Config]" section (make sure the port number matches the value specified in step 1). See the Configuration section above for a complete specification of this file's contents.

Example file contents:

```
[Config]
# Product information.
ProductName=cefclient
ProductVersion=1.0.0

# Required to enable crash dump upload.
ServerURL=http://localhost:8080

# Disable rate limiting so that all crashes are uploaded.
RateLimitEnabled=false
MaxUploadsPerDay=0

[CrashKeys]
# The cefclient sample application sets these values (see step 5 below).
testkey_small1=small
testkey_small2=small
testkey_medium1=medium
testkey_medium2=medium
testkey_large1=large
testkey_large2=large
```

3\. Load one of the following URLs in the CEF-based application to cause a crash:

* Main (browser) process crash:   chrome://inducebrowsercrashforrealz
* Renderer process crash:         chrome://crash
* GPU process crash:              chrome://gpucrash

4\. When the script successfully receives a crash report upload you will see console output like the following:

```
01/10/2017 12:31:23: Dump <id>
```

The "<id>" value is a 16 digit hexadecimal string that uniquely identifies the dump. Crash minidump contents and metadata (product state, command-line flags and crash keys) will be written to the "<id>.dmp" and "<id>.json" files respectively underneath the directory specified in step 1.

On Linux, Breakpad uses the `wget` utility to upload crash dumps, so make sure that utility is installed. If the crash is handled correctly then you should see console output like the following when the client uploads a crash dump:

```text
--2017-01-10 12:31:22--  http://localhost:8080/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: '/dev/fd/3'
Crash dump id: <id>
```

On macOS, when uploading a crash report to the script over HTTP you may receive an error like the following:

```
Transport security has blocked a cleartext HTTP (http://) resource load
since it is insecure. Temporary exceptions can be configured via your app's
Info.plist file.
```

You can work around this error by adding the "NSAppTransportSecurity" key to the Info.plist file in your application's Helper.app bundle (e.g. "tests/cefclient/resources/mac/helper-Info.plist" before building cefclient, or "<appname>.app/Contents/Frameworks/<appname> Helper. app/Contents/Info.plist" in the resulting app bundle):

```html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  
  <key>NSAppTransportSecurity</key>
  <dict>
    
    <key>NSAllowsArbitraryLoads</key>
    <true/>
  </dict>
</dict>
</plist>
```

5\. The cefclient sample application sets test crash key values in the browser and renderer processes. To work properly these values must also be defined in the "[CrashKeys]" section of "crash_reporter.cfg" as shown above.

In [tests/cefclient/browser/client_browser.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/browser/client_browser.cc) (browser process):

```
CefSetCrashKeyValue("testkey_small1", "value1_small_browser");
CefSetCrashKeyValue("testkey_small2", "value2_small_browser");
CefSetCrashKeyValue("testkey_medium1", "value1_medium_browser");
CefSetCrashKeyValue("testkey_medium2", "value2_medium_browser");
CefSetCrashKeyValue("testkey_large1", "value1_large_browser");
CefSetCrashKeyValue("testkey_large2", "value2_large_browser");
```

In [tests/cefclient/renderer/client_renderer.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/renderer/client_renderer.cc) (renderer process):

```
CefSetCrashKeyValue("testkey_small1", "value1_small_renderer");
CefSetCrashKeyValue("testkey_small2", "value2_small_renderer");
CefSetCrashKeyValue("testkey_medium1", "value1_medium_renderer");
CefSetCrashKeyValue("testkey_medium2", "value2_medium_renderer");
CefSetCrashKeyValue("testkey_large1", "value1_large_renderer");
CefSetCrashKeyValue("testkey_large2", "value2_large_renderer");
```

When crashing the browser or renderer processes with cefclient you should verify that the test crash key values are included in the metadata ("<id>.json") file. Some values may be chunked as described in the Configuration section above.

Example metadata for a browser process crash:

```json
{
  "LOG_FATAL": "debug_urls.cc:208: Check failed: false. \n0   Chromium Embedded Framework         0x00000001161a1a0e _ZN4base5debug10StackTraceC2Ev + 30\n1   Chromium Embedded Framework         0x00000001161a1a75 _ZN4base5debug10StackTraceC1Ev + 21\n2   Chromium Embedded Fr",
  "guid": "6ada20da-7306-477e-a715-ada36448a23f",
  "num-switches": "3",
  "pid": "2073",
  "platform": "macos",
  "product": "cefclient",
  "ptype": "browser",
  "switch-1": "--url=chrome:\/\/inducebrowsercrashforrealz",
  "switch-2": "--lang=en-US",
  "testkey_large1": "value1_large_browser", 
  "testkey_large2": "value2_large_browser", 
  "testkey_medium1": "value1_medium_browser", 
  "testkey_medium2": "value2_medium_browser", 
  "testkey_small1": "value1_small_browser", 
  "testkey_small2": "value2_small_browser", 
  "version": "1.0.0",
}
```

Example metadata for a renderer process crash:

```json
{
  "discardable-memory-allocated": "4194304",
  "discardable-memory-free": "3198976",
  "guid": "6ada20da-7306-477e-a715-ada36448a23f",
  "num-switches": "15",
  "origin_mismatch_origin": "https:\/\/www.google.com",
  "origin_mismatch_redirects": "2",
  "origin_mismatch_same_page": "0"
  "origin_mismatch_transition": "1",
  "origin_mismatch_url-1": "https:\/\/www.google.com\/?gws_rd=ssl",
  "pid": "2706",
  "platform": "macos",
  "product": "cefclient",
  "ptype": "renderer",
  "rvinit_main_frame_id": "2",
  "rvinit_proxy_id": "-2",
  "rvinit_view_id": "1",
  "switch-1": "--disable-databases",
  "switch-2": "--lang=en-US",
  "switch-3": "--lang=en-US",
  "switch-4": "--enable-pinch",
  "switch-5": "--num-raster-threads=4",
  "switch-6": "--enable-gpu-rasterization",
  "switch-7": "--enable-zero-copy",
  "switch-8": "--enable-gpu-memory-buffer-compositor-resources",
  "switch-9": "--enable-main-frame-before-activation",
  "switch-10": "--renderer-client-id=3",
  "testkey_large1": "value1_large_renderer", 
  "testkey_large2": "value2_large_renderer", 
  "testkey_medium1": "value1_medium_renderer", 
  "testkey_medium2": "value2_medium_renderer", 
  "testkey_small1": "value1_small_renderer", 
  "testkey_small2": "value2_small_renderer", 
  "v8-ignition": "N",
  "version": "1.0.0",
}
```

Example metadata for a GPU process crash:

```json
{
  "guid": "6ada20da-7306-477e-a715-ada36448a23f",
  "num-switches": "17",
  "pid": "1664",
  "platform": "macos",
  "product": "cefclient",
  "ptype": "gpu-process",
  "switch-1": "--lang=en-US",
  "switch-2": "--supports-dual-gpus=true",
  "switch-3": "--gpu-driver-bug-workarounds=0,1,10,23,25,35,38,45,51,59,61,62,63,64,66,70,71,73,81,82,83,86,88,89",
  "switch-4": "--gpu-vendor-id=0x1002",
  "switch-5": "--gpu-device-id=0x6821",
  "switch-6": "--gpu-driver-vendor",
  "switch-7": "--gpu-driver-version",
  "switch-8": "--gpu-driver-date",
  "switch-9": "--gpu-secondary-vendor-ids=0x8086",
  "switch-10": "--gpu-secondary-device-ids=0x0d26"
  "switch-11": "--gpu-active-vendor-id=0x8086",
  "switch-12": "--gpu-active-device-id=0x0d26",
  "switch-13": "--lang=en-US",
  "version": "1.0.0",
}
```

# Decoding Minidumps

The crash report upload, if enabled, includes the minidump file with exception state, callstacks, stack memory, and loaded modules. The minidump file can be decoded using the `dump_syms` and `minidump_stackwalk` tools from Breakpad as described [here](https://www.chromium.org/developers/decoding-crash-dumps).

The Breakpad tools can be built from a local Chromium checkout on Windows, MacOS and Linux as follows:

1\. Download the Chromium code (for example, by using [CEF tooling](master_build_quick_start.md)).

2\. Write the following contents to the `out/Release/args.gn` file:

```
is_component_build=false
is_debug=false
target_cpu="x64"
is_official_build=true
```

3\. Generate the config and build:

```sh
gn gen out/Release
ninja -C out/Release dump_syms minidump_stackwalk
```

4\. Windows requires the `msdia140.dll` COM DLL. It must be placed next to `dump_syms.exe` or registered with the system:

```
regsvr32 /s msdia140.dll
```

Visual Studio 2022 includes a 64-bit version of this DLL at "C:\Program Files\Microsoft Visual Studio\2022\Professional\DIA SDK\bin\amd64". The 64-bit version 14.29.30133.0 or newer is recommended to avoid failures when loading large (> 4GB) PDB files ([details](https://developercommunity.visualstudio.com/t/pdb-limit-of-4-gib-is-likely-to-be-a-problem-in-a/904784)).

---

### General Usage (`docs/general_usage.md`)

This page provides an overview of CEF3 and general usage information.

**Contents**

- [Introduction](#introduction)
- [Getting Started](#getting-started)
  - [Using a Binary Distribution](#using-a-binary-distribution)
  - [Building from Source Code](#building-from-source-code)
- [Sample Application](#sample-application)
- [Important Concepts](#important-concepts)
  - [C++ Wrapper](#c-wrapper)
  - [Processes](#processes)
  - [Threads](#threads)
  - [Reference Counting](#reference-counting)
  - [Strings](#strings)
  - [Command Line Arguments](#command-line-arguments)
  - [Coordinate Systems](#coordinate-systems)
- [Application Layout](#application-layout)
  - [Windows](#windows)
  - [Linux](#linux)
  - [MacOS](#macos)
- [Application Structure](#application-structure)
  - [Entry-Point Function](#entry-point-function)
    - [Single Executable](#single-executable)
    - [Separate Sub-Process Executable](#separate-sub-process-executable)
  - [Message Loop Integration](#message-loop-integration)
  - [CefSettings](#cefsettings)
  - [CefBrowser and CefFrame](#cefbrowser-and-cefframe)
  - [CefApp](#cefapp)
  - [CefClient](#cefclient)
  - [Browser Life Span](#browser-life-span)
  - [Off-Screen Rendering](#off-screen-rendering)
- [Posting Tasks](#posting-tasks)
- [Inter-Process Communication (IPC)](#inter-process-communication-ipc)
  - [Process Startup Messages](#process-startup-messages)
  - [Process Runtime Messages](#process-runtime-messages)
  - [Asynchronous JavaScript Bindings](#asynchronous-javascript-bindings)
    - [Generic Message Router](#generic-message-router)
    - [Custom Implementation](#custom-implementation)
  - [Synchronous Requests](#synchronous-requests)
- [Network Layer](#network-layer)
  - [Custom Requests](#custom-requests)
    - [Browser-Independent Requests](#browser-independent-requests)
  - [Request Handling](#request-handling)
    - [Generic Resource Manager](#generic-resource-manager)
    - [Scheme Handler](#scheme-handler)
    - [Request Interception](#request-interception)
    - [Response Filtering](#response-filtering)
  - [Other Callbacks](#other-callbacks)
  - [Proxy Resolution](#proxy-resolution)

---

# Introduction

The Chromium Embedded Framework (CEF) is an open source project based on the [Google Chromium](http://www.chromium.org/Home) project. Unlike the Chromium project itself, which focuses mainly on Google Chrome application development, CEF focuses on facilitating embedded browser use cases in third-party applications. CEF insulates the user from the underlying Chromium and Blink code complexity by offering production-quality stable APIs, release branches tracking specific Chromium releases, and binary distributions. Most features in CEF have default implementations that provide rich functionality while requiring little or no integration work from the user. As of this article's publication there are over 100 million installed instances of CEF around the world embedded in products from a wide range of companies and industries. A partial list of companies and products using CEF is available on the [CEF Wikipedia page](http://en.wikipedia.org/wiki/Chromium_Embedded_Framework#Applications_using_CEF). Some use cases for CEF include:

  * Embedding an HTML5-compliant Web browser control in an existing native application.
  * Creating a light-weight native "shell" application that hosts a user interface developed primarily using Web technologies.
  * Rendering Web content "off-screen" in applications that have their own custom drawing frameworks.
  * Acting as a host for automated testing of existing Web properties and applications.

CEF3 is the next generation of CEF based on the multi-process [Chromium Content API](http://www.chromium.org/developers/content-module/content-api). Advantages to CEF3's multi-process architecture include:

  * Improved performance and stability (JavaScript and plugins run in a separate process).
  * Support for Retina displays.
  * GPU acceleration for WebGL and 3D CSS.
  * Cool new features like WebRTC (webcam support) and speech input.
  * Better automated UI testing via the DevTools remote debugging protocol and [ChromeDriver2](https://code.google.com/p/chromedriver/wiki/ChromeDriver2).
  * Faster access to current and future Web features and standards.

This document introduces the general concepts involved when developing an application using CEF3.

# Getting Started

## Using a Binary Distribution

Binary distributions of CEF3 are available from the [project Downloads page](https://cef-builds.spotifycdn.com/index.html). They contain all files necessary to build a particular version of CEF3 on a particular platform (Windows, MacOS or Linux). See the [Tutorial](tutorial.md) page for detailed instructions on how to create a simple application using the CEF3 binary distribution.

No matter the platform all binary distributions share the same general structure:

  * **CMakeLists.txt** provides the [CMake configuration](https://cmake.org/overview/) for building the test applications included with the binary distribution. Platform-specific build instructions are provided as comments at the top of this file.
  * **Debug** contains a debug build the CEF shared library (libcef) and any other libraries required to run on the platform.
  * **include** contains all required CEF header files.
  * **libcef\_dll** contains the source code for the libcef\_dll\_wrapper static library that all applications using the CEF C++ API must link against. See the "C++ Wrapper" section for more information.
  * **Release** contains a release build the CEF shared library (libcef) and any other libraries required to run on the platform.
  * **Resources** contains resources required by applications using CEF (Windows and Linux only). This includes .pak files (binary files with globbed resources) and potentially other files such depending on the platform.
  * **tests/cefclient** contains the cefclient sample application configured to build using the files in the binary distribution. This application demonstrates a wide range of CEF functionalities.
  * **tests/cefsimple** contains the cefsimple sample application configured to build using the files in the binary distribution. This application demonstrates the minimal functionality required to create a browser window.
  * **tests/ceftests** contains the ceftests sample application configured to build using the files in the binary distribution. This application provides unit test coverage for CEF APIs and functionality.

Each binary distribution also contains a README.txt file that describes the platform-specific distribution in greater detail and a LICENSE.txt file that contains CEF's BSD license. When distributing an application based on CEF you should include the license text somewhere in your application's distribution. For example, you can list it on an "About" or "Credits" page in your application's UI, or in the documentation bundled with your application. License and credit information is also available inside of a CEF3 browser window by loading "about:license" and "about:credits" respectively.

Applications based on CEF binary distributions can be built using standard platform build tools. This includes Visual Studio on Windows, Xcode on MacOS and gcc/make on Linux. The project Downloads page contains information about the OS and build tool versions required for specific binary releases. When building on Linux also pay careful attention to the listed package dependencies.

## Building from Source Code

CEF can be built from source code either locally or using automated build systems like [TeamCity](http://www.jetbrains.com/teamcity/). This requires the download of Chromium and CEF source code via Git. The Chromium code base is quite large and building Chromium from source code is only recommended on moderately powerful machines with more than 8GB of RAM. Detailed instructions for building Chromium and CEF from source code are available on the [Branches And Building](branches_and_building.md) page.

# Sample Application

The cefclient sample application is a complete working example of CEF integration and is included in source code form with each binary distribution. The easiest way to create a new application using CEF is to start with the cefclient application and remove the parts that you don't need. Many of the examples in this document originate from the cefclient application.

# Important Concepts

There are some important underlying concepts to developing CEF3-based applications that should be understood before proceeding.

## C++ Wrapper

The libcef shared library exports a C API that isolates the user from the CEF runtime and code base. The libcef\_dll\_wrapper project, which is distributed in source code form as part of the binary release, wraps this exported C API in a C++ API that is then linked into the client application. The code for this C/C++ API translation layer is automatically generated by the [translator](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt) tool. Direct usage of the C API is described on the [Using The CAPI](using_the_capi.md) page.

## Processes

CEF3 runs using multiple processes. The main process which handles window creation, UI and network access is called the "browser" process. This is generally the same process as the host application and the majority of the application logic will run in the browser process. Blink rendering and JavaScript execution occur in a separate "render" process. Some application logic, such as JavaScript bindings and DOM access, will also run in the render process. The default [process model](http://www.chromium.org/developers/design-documents/process-models) will spawn a new render process for each unique origin (scheme + domain). Other processes will be spawned as needed, such as the "gpu" process to handle [accelerated compositing](http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome).

By default the main application executable will be spawned multiple times to represent separate processes. This is handled via command-line flags that are passed into the CefExecuteProcess function. If the main application executable is large, takes a long time to load, or is otherwise unsuitable for non-browser processes the host can use a separate executable for those other processes. This can be configured via the CefSettings.browser\_subprocess\_path variable. See the "Application Structure" section for more information.

The separate processes spawned by CEF3 communicate using Inter-Process Communication (IPC). Application logic implemented in the browser and render processes can communicate by sending asynchronous messages back and forth. [Java Script Integration](javascript_integration.md) in the render process can expose asynchronous APIs that are handled in the browser process. See the "Inter-Process Communication" section for more information.

Platform-specific debugging tips are also available for [Windows](https://www.chromium.org/developers/how-tos/debugging-on-windows), [MacOS](https://chromium.googlesource.com/chromium/src/+/main/docs/mac/debugging.md) and [Linux](https://chromium.googlesource.com/chromium/src/+/master/docs/linux/debugging.md).

## Threads

Each process in CEF3 runs multiple threads. For a complete list of threads see the [cef\_thread\_id\_t](https://github.com/chromiumembedded/cef/blob/81e7748fb5008295c2a1f2d75b0f0c907c1fdfe8/include/internal/cef_types.h#L1366) enumeration. These are some of the commonly-referenced threads:

  * **TID\_UI** thread is the main thread in the browser process. This thread will be the same as the main application thread if CefInitialize() is called with a CefSettings.multi\_threaded\_message\_loop value of false.
  * **TID\_IO** thread is used in the browser process to handle IPC and network messages.
  * **TID\_FILE\_\*** threads are used in the browser process to interact with the file system. Blocking operations should only be performed on this thread or a [CefThread](https://cef-builds.spotifycdn.com/docs/stable.html?classCefThread.html) created by the client application.
  * **TID\_RENDERER** thread is the main thread in the renderer process. All Blink and V8 interation must take place on this thread.

Due to the multi-threaded nature of CEF it's important to use message passing or locking to protect data members from access on multiple threads. The CefPostTask family of functions support easy asynchronous message passing between threads. See the "Posting Tasks" section for more information.

The current thread can be verified using the CefCurrentlyOn() function. The CEF sample applications use the following defines to verify that methods are executed on the expected thread. These defines are included in the [include/wrapper/cef\_helpers.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_helpers.h) header file.

```cpp
#define CEF_REQUIRE_UI_THREAD() DCHECK(CefCurrentlyOn(TID_UI));
#define CEF_REQUIRE_IO_THREAD() DCHECK(CefCurrentlyOn(TID_IO));
#define CEF_REQUIRE_FILE_BACKGROUND_THREAD() \
 DCHECK(CefCurrentlyOn(TID_FILE_BACKGROUND));
#define CEF_REQUIRE_FILE_USER_VISIBLE_THREAD() \
 DCHECK(CefCurrentlyOn(TID_FILE_USER_VISIBLE));
#define CEF_REQUIRE_FILE_USER_BLOCKING_THREAD() \
 DCHECK(CefCurrentlyOn(TID_FILE_USER_BLOCKING));
#define CEF_REQUIRE_RENDERER_THREAD() DCHECK(CefCurrentlyOn(TID_RENDERER));
```

To support synchronized access to blocks of code CEF provides base::Lock and base::AutoLock types via the [include/base/cef\_lock.h](https://github.com/chromiumembedded/cef/blob/master/include/base/cef_lock.h) header file. For example:

```cpp
// Include the necessary header.
#include "include/base/cef_lock.h"

// Class declaration.
class MyClass : public CefBaseRefCounted {
 public:
  MyClass() : value_(0) {}
  // Method that may be called on multiple threads.
  void IncrementValue();
 private:
  // Value that may be accessed on multiple theads.
  int value_;
  // Lock used to protect access to |value_|.
  base::Lock lock_;
  IMPLEMENT_REFCOUNTING(MyClass);
};

// Class implementation.
void MyClass::IncrementValue() {
  // Acquire the lock for the scope of this method.
  base::AutoLock lock_scope(lock_);
  // |value_| can now be modified safely.
  value_++;
}
```

## Reference Counting

All framework classes implement the CefBase[RefCounted|Scoped] interface and all instance pointers are handled using the CefRefPtr smart pointer implementation that automatically handles reference counting via calls to AddRef() and Release(). The easiest way to implement these classes is as follows:

```cpp
class MyClass : public CefBaseRefCounted {
 public:
  // Various class methods here...

 private:
  // Various class members here...

  IMPLEMENT_REFCOUNTING(MyClass);  // Provides atomic refcounting implementation.
};

// References a MyClass instance
CefRefPtr<MyClass> my_class = new MyClass();
```

## Strings

CEF defines its own data structure for representing strings. This is for a few different reasons:

  * The libcef library and the host application may use different runtimes for managing heap memory. All objects, including strings, need to be freed using the same runtime that allocated the memory.
  * The libcef library can be compiled to support different underlying string types (UTF8, UTF16 or wide). The default is UTF16 but it can be changed by modifying the defines in [cef\_string.h](https://github.com/chromiumembedded/cef/blob/master/include/internal/cef_string.h) and recompiling CEF. When choosing the wide string type keep in mind that the size will vary depending on the platform.

For UTF16 the string structure looks like this:

```cpp
typedef struct _cef_string_utf16_t {
  char16_t* str;  // Pointer to the string
  size_t length;  // String length
  void (*dtor)(char16_t* str);  // Destructor for freeing the string on the correct heap
} cef_string_utf16_t;
```

The selected string type is then typedef'd to the generic type:

```cpp
typedef char16_t cef_char_t;
typedef cef_string_utf16_t cef_string_t;
```

CEF provides a number of C API functions for operating on the CEF string types (mapped via #defines to the type-specific functions). For example:

  * **cef\_string\_set** will assign a string value to the structure with or without copying the value.
  * **cef\_string\_clear** will clear the string value.
  * **cef\_string\_cmp** will compare two string values.

CEF also provides functions for converting between all supported string types (ASCII, UTF8, UTF16 and wide). See the [cef\_string.h](https://github.com/chromiumembedded/cef/blob/master/include/internal/cef_string.h) and [cef\_string\_types.h](https://github.com/chromiumembedded/cef/blob/master/include/internal/cef_string_types.h) headers for the complete list of functions.

Usage of CEF strings in C++ is simplified by the CefString class. CefString provides automatic conversion to and from std::string (UTF8) and std::wstring (wide) types. It can also be used to wrap an existing cef\_string\_t structure for assignment purposes.

Assignment to and from std::string:

```cpp
std::string str = "Some UTF8 string";

// Equivalent ways of assigning |str| to |cef_str|. Conversion from UTF8 will occur if necessary.
CefString cef_str(str);
cef_str = str;
cef_str.FromString(str);

// Equivalent ways of assigning |cef_str| to |str|. Conversion to UTF8 will occur if necessary.
str = cef_str;
str = cef_str.ToString();
```

Assignment  to and from std::wstring:

```cpp
std::wstring str = "Some wide string";

// Equivalent ways of assigning |str| to |cef_str|. Conversion from wide will occur if necessary.
CefString cef_str(str);
cef_str = str;
cef_str.FromWString(str);

// Equivalent ways of assigning |cef_str| to |str|. Conversion to wide will occur if necessary.
str = cef_str;
str = cef_str.ToWString();
```

Use the FromASCII() method if you know that the format is ASCII:

```cpp
const char* cstr = "Some ASCII string";
CefString cef_str;
cef_str.FromASCII(cstr);
```

Some structures like CefSettings have cef\_string\_t members. CefString can be used to simplify the assignment to those members:

```cpp
CefSettings settings;
const char* path = "/path/to/log.txt";

// Equivalent assignments.
CefString(&settings.log_file).FromASCII(path);
cef_string_from_ascii(path, strlen(path), &settings.log_file);
```

## Command Line Arguments

Many features in CEF3 and Chromium can be configured using command line arguments. These arguments take the form "--some-argument[=optional-param]" and are passed into CEF via CefExecuteProcess() and the CefMainArgs structure (see the "Application Structure" section below).

  * To disable processing of arguments from the command line set CefSettings.command\_line\_args\_disabled to true before passing the CefSettings structure into CefInitialize().
  * To specify CEF/Chromium command line arguments inside the host application implement the CefApp::OnBeforeCommandLineProcessing() method.
  * To pass application-specific (non-CEF/Chromium) command line arguments to sub-processes implement the CefBrowserProcessHandler::OnBeforeChildProcessLaunch() method.

See comments in [shared/common/client\_switches.cc](https://github.com/chromiumembedded/cef/blob/master/tests/shared/common/client_switches.cc) for more information on how to discover supported CEF/Chromium command line switches.

## Coordinate Systems

Browser applications use different coordinate systems depending on the context. Screen/window coordinates are generally represented as density independent pixel (DIP) coordinates with upper-left origin. These DIP coordinates will be passed to [Views APIs](https://github.com/chromiumembedded/cef/tree/master/include/views) and browser callbacks such as OnAutoResize and OnContentsBoundsChange. JavaScript and CSS mostly use CSS pixels which are similar to DIP coordinates but also reflect browser zoom settings [(details)](https://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_view/Viewport_concepts). Applications using other platform APIs/toolkits may also need to convert to/from specific device coordinate systems.

Important details related to coordinate system usage in CEF:

* DIP coordinate and CSS pixel factors will be the same when browser zoom is set to 100%.
* Views-hosted browsers are aware of the containing [CefWindow](https://cef-builds.spotifycdn.com/docs/stable.html?classCefWindow.html) and browser callbacks such as OnContentsBoundsChange will report frame bounds for that window. Same for browsers with a native parent NSWindow on macOS.
* Windowless (off-screen) browsers can be made aware of containing screen/window bounds by implementing the appropriate [CefRenderHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRenderHandler.html) methods (GetScreenInfo, GetRootScreenRect, GetViewRect).
* Other browsers (native hosted or windowless) will report bounds for the browser content only.
    * The client application is responsible for converting bounds and enlarging to include native controls and/or window frame (see below).
* DIP conversion requirements differ by platform API/toolkit.
    * DIP coordinates convert to device coordinates based on the device scale factor.
        * By default the device scale factor will match the associated display (e.g. user/system-level display settings).
        * The device scale factor can be changed to a non-default value globally by using the `--force-device-scale-factor=[float]` command-line flag.
        * On macOS a non-default device scale factor impacts rendering quality but does not impact the DIP conversion itself.
        * Windowed browsers should convert DIP coordinates using [CefDisplay](https://cef-builds.spotifycdn.com/docs/stable.html?classCefDisplay.html) methods.
        * Windowless browsers should convert DIP coordinates using the [device_scale_factor](https://cef-builds.spotifycdn.com/docs/stable.html?structcef__screen__info__t.html#a82e584007cd1cc85fa837ae699866305) that was last configured via [GetScreenInfo](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRenderHandler.html#a68a34e2102f3cca48e054f0c27c365da).
    * Views API methods use DIP coordinates directly.
    * Windows API methods ([SetWindowPos](ttps://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos), [AdjustWindowRectEx](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-adjustwindowrectex), etc.) expect [device (pixel) coordinates](https://learn.microsoft.com/en-us/windows/win32/gdi/window-coordinate-system).
        * Use the static CefDisplay conversion methods on Windows for best (multi-dpi-aware) results.
        * The DIP conversion factor may be different from the [DPI awareness settings](https://learn.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows) used with native controls. WinAPI functions like [GetDpiForWindow](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow) should be used to convert native control coordinates.
    * Linux platform toolkits (GTK, etc) usually expect root window (pixel) coordinates.
    * MacOS (Cocoa) API methods use DIP coordinates as device coordinates but with a [different](https://developer.apple.com/library/archive/documentation/General/Devpedia-CocoaApp-MOSX/CoordinateSystem.html) (lower-left) origin.
* JavaScript can convert CSS pixels to device coordinates using [window.devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio).
</ul>

Coordinate system behavior can be explored further in the cefclient sample app by running with the `--url=https://tests/window` command-line flag.

# Application Layout

Application layout can differ significantly depending on the platform. For example, on MacOS your application layout must follow a specific app bundle structure. Windows and Linux are more flexible, allowing you to customize the location where CEF libraries and resources are stored. For a complete working example of the required layout you can download a "Sample Application" from the [project Downloads page](https://cef-builds.spotifycdn.com/index.html). Some distributed files are required and some are optional. Requirements and additional information for each file can be found in the binary distribution README.txt file.

## Windows

On Windows the default layout places the libcef library and related resources next to the application executable. The directory structure looks like this for 4692 branch:

```text
Application/
    cefclient.exe  <= cefclient application executable
    libcef.dll <= main CEF library
    icudtl.dat <= unicode support data
    chrome_100_percent.pak, chrome_200_percent.pak, resources.pak <= non-localized resources and strings
    snapshot_blob.bin, v8_context_snapshot.bin <= V8 initial snapshot
    locales/
        en-US.pak, ... <= locale-specific resources and strings
```

The location of the CEF libraries and resource files can be customized using the CefSettings structure (see the README.txt file or "CefSettings" section for details). The cefclient application on Windows compiles in resources via the BINARY resource type in [cefclient/resources/win/cefclient.rc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/resources/win/cefclient.rc) but an application could just as easily load resources from the local file system.

## Linux

On Linux the default layout places the libcef library and related resources next to the application executable. Note however that there's a discrepancy between where libcef.so is located in the client distribution and where it's located in the binary distribution that you build yourself. The location depends on how the linker rpath value is set when building the application executable. For example, a value of "-Wl,-rpath,." ("." meaning the current directory) will allow you to place libcef.so next to the application executable. The path to libcef.so can also be specified using the LD\_LIBRARY\_PATH environment variable. The directory structure looks like this for 4692 branch:

```text
Application/
    cefclient  <= cefclient application executable
    chrome-sandbox <= sandbox support binary
    libcef.so <= main CEF library
    icudtl.dat <= unicode support data
    chrome_100_percent.pak, chrome_200_percent.pak, resources.pak <= non-localized resources and strings
    snapshot_blob.bin, v8_context_snapshot.bin <= V8 initial snapshot
    locales/
        en-US.pak, ... <= locale-specific resources and strings
    files/
        binding.html, ... <= cefclient application resources
```

The location of the CEF libraries and resource files can be customized using the CefSettings structure (see the README.txt file of "CefSettings" section for details).

## MacOS

The application (app bundle) layout on MacOS is mandated by the Chromium implementation and consequently is not very flexible. The directory structure looks like this for 4692 branch:

```text
cefclient.app/
    Contents/
        Frameworks/
            Chromium Embedded Framework.framework/
                Chromium Embedded Framework <= main application library
                Resources/
                    chrome_100_percent.pak, chrome_200_percent.pak, resources.pak, ... <= non-localized resources and strings
                    icudtl.dat <= unicode support data
                    snapshot_blob.bin, v8_context_snapshot.bin <= V8 initial snapshot
                    en.lproj/, ... <= locale-specific resources and strings
            cefclient Helper.app/
                Contents/
                    Info.plist
                    MacOS/
                        cefclient Helper <= helper executable
                    Pkginfo
        Info.plist
        MacOS/
            cefclient <= cefclient application executable
        Pkginfo
        Resources/
            binding.html, ... <= cefclient application resources
```

The "Chromium Embedded Framework.framework" is an [unversioned framework](http://src.chromium.org/viewvc/chrome/trunk/src/build/mac/copy_framework_unversioned.sh?view=markup) that contains all CEF binaries and resources. Executables (cefclient, cefclient Helper, etc) dynamically load the CEF Framework as described [here](https://groups.google.com/d/msg/cef-announce/Fith0A3kWtw/6ds_mJVMCQAJ).

The "cefclient Helper" app is used for executing separate processes (renderer, plugin, etc) with different characteristics. It needs to have a separate app bundle and Info.plist file so that, among other things, it doesn't show dock icons.

# Application Structure

Every CEF3 application has the same general structure.

  * Provide an entry-point function that initializes CEF and runs either sub-process executable logic or the CEF message loop.
  * Provide an implementation of [CefApp](https://cef-builds.spotifycdn.com/docs/stable.html?classCefApp.html) to handle process-specific callbacks.
  * Provide an implementation of [CefClient](https://cef-builds.spotifycdn.com/docs/stable.html?classCefClient.html) to handle browser-instance-specific callbacks.
  * Call CefBrowserHost::CreateBrowser() to create a browser instance and manage the browser life span using [CefLifeSpanHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefLifeSpanHandler.html).

## Entry-Point Function

As described in the "Processes" section a CEF3 application will run multiple processes. The processes can all use the same executable or a separate executable can be specified for the sub-processes. Execution of the process begins in the entry-point function. Complete platform-specific examples for Windows, Linux and MacOS are available in [cefclient/cefclient\_win.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/cefclient_win.cc), [cefclient/cefclient\_gtk.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/cefclient_gtk.cc) and [cefclient/cefclient\_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/cefclient_mac.mm) respectively.

When launching sub-processes CEF will specify configuration information using the command-line that must be passed into the CefExecuteProcess function via the CefMainArgs structure. The definition of CefMainArgs is platform-specific. On Linux and MacOS it accepts the argc and argv values which are passed into the [main() function](https://en.wikipedia.org/wiki/Main_function).

```
CefMainArgs main_args(argc, argv);
```

On Windows it accepts the instance handle (HINSTANCE) which is passed into the [wWinMain() function](http://msdn.microsoft.com/en-us/library/windows/desktop/ff381406(v=vs.85).aspx). The instance handle is also retrievable via GetModuleHandle(nullptr).

```
CefMainArgs main_args(hInstance);
```

### Single Executable

When running as a single executable the entry-point function is required to differentiate between the different process types. The single executable structure is supported on Windows and Linux but not on MacOS.

```cpp
// Program entry-point function.
int main(int argc, char* argv[]) {
  // Structure for passing command-line arguments.
  // The definition of this structure is platform-specific.
  CefMainArgs main_args(argc, argv);

  // Implementation of the CefApp interface.
  CefRefPtr<MyApp> app(new MyApp);

  // Execute the sub-process logic, if any. This will either return immediately for the browser
  // process or block until the sub-process should exit.
  int exit_code = CefExecuteProcess(main_args, app.get());
  if (exit_code >= 0) {
    // The sub-process terminated, exit now.
    return exit_code;
  }

  // Populate this structure to customize CEF behavior.
  CefSettings settings;

  // Initialize CEF in the main process.
  CefInitialize(main_args, settings, app.get());

  // Run the CEF message loop. This will block until CefQuitMessageLoop() is called.
  CefRunMessageLoop();

  // Shut down CEF.
  CefShutdown();

  return 0;
}
```

### Separate Sub-Process Executable

When using a separate sub-process executable you need two separate executable projects and two separate entry-point functions.

Main application entry-point function:

```cpp
// Program entry-point function.
int main(int argc, char* argv[]) {
  // Load the CEF framework library at runtime instead of linking directly
  // as required by the macOS sandbox implementation.
  CefScopedLibraryLoader library_loader;
  if (!library_loader.LoadInMain())
    return 1;

  // Structure for passing command-line arguments.
  // The definition of this structure is platform-specific.
  CefMainArgs main_args(argc, argv);

  // Implementation of the CefApp interface.
  CefRefPtr<MyApp> app(new MyApp);

  // Populate this structure to customize CEF behavior.
  CefSettings settings;

  // Specify the path for the sub-process executable.
  CefString(&settings.browser_subprocess_path).FromASCII("/path/to/subprocess");

  // Initialize CEF in the main process.
  CefInitialize(main_args, settings, app.get());

  // Run the CEF message loop. This will block until CefQuitMessageLoop() is called.
  CefRunMessageLoop();

  // Shut down CEF.
  CefShutdown();

  return 0;
}
```

Sub-process application entry-point function:

```cpp
// Program entry-point function.
int main(int argc, char* argv[]) {
  // Initialize the macOS sandbox for this helper process.
  CefScopedSandboxContext sandbox_context;
  if (!sandbox_context.Initialize(argc, argv))
    return 1;

  // Load the CEF framework library at runtime instead of linking directly
  // as required by the macOS sandbox implementation.
  CefScopedLibraryLoader library_loader;
  if (!library_loader.LoadInHelper())
    return 1;

  // Structure for passing command-line arguments.
  // The definition of this structure is platform-specific.
  CefMainArgs main_args(argc, argv);

  // Implementation of the CefApp interface.
  CefRefPtr<MyApp> app(new MyApp);

  // Execute the sub-process logic. This will block until the sub-process should exit.
  return CefExecuteProcess(main_args, app.get());
}
```

## Message Loop Integration

CEF can also integrate with an existing application message loop instead of running its own message loop. There are two ways to do this.

  1. Call CefDoMessageLoopWork() on a regular basis instead of calling CefRunMessageLoop(). Each call performs a single iteration of the CEF message loop. Call it on the main application thread, with CefSettings.multi\_threaded\_message\_loop = false, while continuing to process the host application's native events. Calling too infrequently will starve CEF work and negatively impact browser performance; calling too frequently will increase CPU usage.
  1. Set CefSettings.multi\_threaded\_message\_loop = true (Windows and Linux only). This will cause CEF to run the browser UI thread on a separate thread from the main application thread. With this approach neither CefDoMessageLoopWork() nor CefRunMessageLoop() need to be called. CefInitialize() and CefShutdown() should still be called on the main application thread. You will need to provide your own mechanism for communicating with the main application thread (see for example the message window usage in cefclient\_win.cpp). You can test this mode in cefclient on Windows or Linux by running with the "--multi-threaded-message-loop" command-line flag.

When using CefDoMessageLoopWork(), enabling CefSettings.external\_message\_pump lets [CefBrowserProcessHandler::OnScheduleMessagePumpWork](https://cef-builds.spotifycdn.com/docs/stable.html?classCefBrowserProcessHandler.html#a7ff7d1618399ede096ba16486a71d76e) request earlier processing. These callbacks supplement periodic pumping: they do not provide a complete sequence of requests for processing all CEF work. The application must continue scheduling CefDoMessageLoopWork() calls even when no callback is received. This requirement applies on all platforms.

The callback may run on any thread. Marshal each scheduling request to the main application thread. For a delay of zero or less, schedule processing reasonably soon. For a positive delay, replace the pending scheduled call with one after the requested delay or the application's maximum pumping interval, whichever is shorter. After processing, ensure that another call remains scheduled within that interval, even if CEF has requested no further work. Avoid recursive calls to CefDoMessageLoopWork(); if a request is handled while a call is active, defer the additional work until that call returns.

The [shared external-pump example](https://github.com/chromiumembedded/cef/blob/master/tests/shared/browser/main_message_loop_external_pump.cc) uses one-shot timers that are rearmed as needed, with a maximum delay of approximately 33 milliseconds (`1000 / 30`). This interval is the example's scheduling policy, not a guaranteed rendering frame rate. You can test this mode in cefclient with the "--external-message-pump" command-line flag. The example is a simple integration and does not handle all cases. If a nested native message loop is entered during a CefDoMessageLoopWork() call, the example's reentrancy guard defers further CEF processing until that call returns. Applications that require CEF work to continue during such loops need additional integration. See the [example's header](https://github.com/chromiumembedded/cef/blob/master/tests/shared/browser/main_message_loop_external_pump.h) and Chromium's platform-specific `base/message_loop/message_pump_*` implementations for additional guidance.

## CefSettings

The CefSettings structure allows configuration of application-wide CEF settings. Some commonly configured members include:

  * **browser\_subprocess\_path** The path to a separate executable that will be launched for sub-processes. See the "Separate Sub-Process Executable" section for more information.
  * **multi\_threaded\_message\_loop** Set to true to have the browser process message loop run in a separate thread. See the "Message Loop Integration" section for more information.
  * **command\_line\_args\_disabled** Set to true to disable configuration of browser process features using standard CEF and Chromium command-line arguments. See the "Command Line Arguments" section for more information.
  * **cache\_path** The location where cache data will be stored on disk. If empty an in-memory cache will be used for some features and a temporary disk cache will be used for others. HTML5 databases such as localStorage will only persist across sessions if a cache path is specified.
  * **locale** The locale string that will be passed to Blink. If empty the default locale of "en-US" will be used. This value is ignored on Linux where locale is determined using environment variable parsing with the precedence order: LANGUAGE, LC\_ALL, LC\_MESSAGES and LANG. Also configurable using the "lang" command-line switch.
  * **log\_file** The directory and file name to use for the debug log. If empty, the default name of "debug.log" will be used and the file will be written to the application directory. Also configurable using the "log-file" command-line switch.
  * **log\_severity** The log severity. Only messages of this severity level or higher will be logged. Also configurable using the "log-severity" command-line switch with a value of "verbose", "info", "warning", "error", "error-report" or "disable".
  * **resources\_dir\_path** The fully qualified path for the resources directory. If this value is empty the cef.pak and/or devtools\_resources.pak files must be located in the module directory on Windows/Linux or the app bundle Resources directory on MacOS. Also configurable using the "resources-dir-path" command-line switch.
  * **locales\_dir\_path** The fully qualified path for the locales directory. If this value is empty the locales directory must be located in the module directory. This value is ignored on MacOS where pack files are always loaded from the app bundle Resources directory. Also configurable using the "locales-dir-path" command-line switch.
  * **remote\_debugging\_port** Set to a value between 1024 and 65535 to enable remote debugging on the specified port. For example, if 8080 is specified the remote debugging URL will be http://localhost:8080. CEF can be remotely debugged from any CEF or Chrome browser window. Also configurable using the "remote-debugging-port" command-line switch.

## CefBrowser and CefFrame

The [CefBrowser](https://cef-builds.spotifycdn.com/docs/stable.html?classCefBrowser.html) and [CefFrame](https://cef-builds.spotifycdn.com/docs/stable.html?classCefFrame.html) objects are used for sending commands to the browser and for retrieving state information in callback methods. Each CefBrowser object will have a single main CefFrame object representing the top-level frame and zero or more CefFrame objects representing sub-frames. For example, a browser that loads two iframes will have three CefFrame objects (the top-level frame and the two iframes).

To load a URL in the browser main frame:

```
browser->GetMainFrame()->LoadURL(some_url);
```

To navigate the browser backwards:

```
browser->GoBack();
```
To retrieve the main frame HTML contents:

```cpp
// Implementation of the CefStringVisitor interface.
class Visitor : public CefStringVisitor {
 public:
  Visitor() {}

  // Called asynchronously when the HTML contents are available.
  virtual void Visit(const CefString& string) override {
    // Do something with |string|...
  }

  IMPLEMENT_REFCOUNTING(Visitor);
};

browser->GetMainFrame()->GetSource(new Visitor());
```

CefBrowser and CefFrame objects exist in both the browser process and the render process. Host behavior can be controlled in the browser process via the CefBrowser::GetHost() method. For example, the native handle for a windowed browser can be retrieved as follows:

```cpp
// CefWindowHandle is defined as HWND on Windows, NSView* on MacOS
// and (usually) X11 Window on Linux.
CefWindowHandle window_handle = browser->GetHost()->GetWindowHandle();
```

Other methods are available for history navigation, loading of strings and requests, sending edit commands, retrieving text/html contents, and more. See the class documentation for the complete list of supported methods.

## CefApp

The [CefApp](https://cef-builds.spotifycdn.com/docs/stable.html?classCefApp.html) interface provides access to process-specific callbacks. Important callbacks include:

  * **OnBeforeCommandLineProcessing** which provides the opportunity to programmatically set command-line arguments. See the "Command Line Arguments" section for more information.
  * **OnRegisterCustomSchemes** which provides an opportunity to register custom schemes. See the ""Request Handling" section for more information.
  * **GetBrowserProcessHandler** which returns the handler for functionality specific to the browser process including the OnContextInitialized() method.
  * **GetRenderProcessHandler** which returns the handler for functionality specific to the render process. This includes JavaScript-related callbacks and process messages. See the [Java Script Integration](javascript_integration.md) page and the "Inter-Process Communication" section for more information.

An example CefApp implementation can be seen in [cefsimple/simple\_app.h](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_app.h) and [cefsimple/simple\_app.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_app.cc).

## CefClient

The [CefClient](https://cef-builds.spotifycdn.com/docs/stable.html?classCefClient.html) interface provides access to browser-instance-specific callbacks. A single CefClient instance can be shared among any number of browsers. Important callbacks include:

  * Handlers for things like browser life span, context menus, dialogs, display notifications, drag events, focus events, keyboard events and more. The majority of handlers are optional. See the class documentation for the side effects, if any, of not implementing a specific handler.
  * **OnProcessMessageReceived** which is called when an IPC message is received from the render process. See the "Inter-Process Communication" section for more information.

An example CefClient implementation can be seen in [cefsimple/simple\_handler.h](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler.h) and [cefsimple/simple\_handler.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler.cc).

## Browser Life Span

Browser life span begins with a call to CefBrowserHost::CreateBrowser() or CefBrowserHost::CreateBrowserSync(). Convenient places to execute this logic include the  CefBrowserProcessHandler::OnContextInitialized() callback or platform-specific message handlers like WM\_CREATE on Windows.

```cpp
// Information about the window that will be created including parenting, size, etc.
// The definition of this structure is platform-specific.
CefWindowInfo info;
// On Windows for example...
info.SetAsChild(parent_hwnd, client_rect);

// Customize this structure to control browser behavior.
CefBrowserSettings settings;

// CefClient implementation.
CefRefPtr<MyClient> client(new MyClient);

// Create the browser asynchronously. Initially loads the Google URL.
CefBrowserHost::CreateBrowser(info, client.get(), "http://www.google.com", settings, nullptr, nullptr);
```

The [CefLifeSpanHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefLifeSpanHandler.html) class provides the callbacks necessary for managing browser life span. Below is an extract of the relevant methods and members.

```cpp
class MyClient : public CefClient,
                 public CefLifeSpanHandler,
                 ... {
  // CefClient methods.
  virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override {
    return this;
  }

  // CefLifeSpanHandler methods.
  void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
  bool DoClose(CefRefPtr<CefBrowser> browser) override;
  void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;

  // Member accessors.
  CefRefPtr<CefBrowser> GetBrower() const { return browser_; }
  bool IsClosing() const { return is_closing_; }

 private:
  CefRefPtr<CefBrowser> browser_;
  int browser_id_ = -1;  // invalid value
  int browser_count_ = 0;
  bool is_closing_ = false;

  IMPLEMENT_REFCOUNTING(MyClient);
};
```

The OnAfterCreated() method will be called immediately after the browser object is created. The host application can use this method to keep a reference to the main browser object.

```cpp
void MyClient::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  // Must be executed on the UI thread.
  REQUIRE_UI_THREAD();
 
  if (!browser_) {
    // Keep a reference to the main browser.
    browser_ = browser;
    browser_id_ = browser->GetIdentifier();
  }

  // Keep track of how many browsers currently exist.
  browser_count_++;
}
```

To destroy the browser call CefBrowserHost::CloseBrowser().

```cpp
// Notify the browser window that we would like to close it. This will result in a call to 
// MyHandler::DoClose() if the JavaScript 'onbeforeunload' event handler allows it.
browser->GetHost()->CloseBrowser(false);
```

If the browser is parented to another window then the close event may originate in the OS function for that parent window (for example, by clicking the X on the parent window). The parent window then needs to call CloseBrowser(false) and wait for a second OS close event to indicate that the browser has allowed the close. The second OS close event will not be sent if the close is canceled by a JavaScript 'onbeforeunload' event handler or by the DoClose() callback. Notice the IsClosing() check in the below examples -- it will return false for the first OS close event and true for the second (after DoClose is called).

Handling in the parent window WndProc on Windows:

```cpp
case WM_CLOSE:
  if (g_handler && !g_handler->IsClosing()) {
    CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
    if (browser) {
      // Notify the browser window that we would like to close it. This will result in a call to 
      // MyHandler::DoClose() if the JavaScript 'onbeforeunload' event handler allows it.
      browser->GetHost()->CloseBrowser(false);

      // Cancel the close.
      return 0;
    }
  }

  // Allow the close.
  break;

case WM_DESTROY:
  // Quitting CEF is handled in MyHandler::OnBeforeClose().
  return 0;
}
```

Handling the "delete\_event" signal on Linux:

```cpp
gboolean delete_event(GtkWidget* widget, GdkEvent* event,
                      GtkWindow* window) {
  if (g_handler && !g_handler->IsClosing()) {
    CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
    if (browser) {
      // Notify the browser window that we would like to close it. This will result in a call to 
      // MyHandler::DoClose() if the JavaScript 'onbeforeunload' event handler allows it.
      browser->GetHost()->CloseBrowser(false);

      // Cancel the close.
      return TRUE;
    }
  }

  // Allow the close.
  return FALSE;
}
```

Shutdown on OS X is more complicated. See comments in [cefsimple/cefsimple\_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_mac.mm) for a complete understanding of how shutdown works on that platform.

The DoClose() method sets the is\_closing\_ flag and returns false to send the second OS close event.

```cpp
bool MyClient::DoClose(CefRefPtr<CefBrowser> browser) {
  // Must be executed on the UI thread.
  REQUIRE_UI_THREAD();

  // Closing the main window requires special handling. See the DoClose()
  // documentation in the CEF header for a detailed description of this
  // process.
  if (browser_id_ == browser->GetIdentifier()) {
    // Set a flag to indicate that the window close should be allowed.
    is_closing_ = true;
  }

  // Allow the close. For windowed browsers this will result in the OS close
  // event being sent.
  return false;
}
```

When the OS function receives the second OS close event it allows the parent window to actually close. This then results in a call to OnBeforeClose(). Make sure to release any references to the browser object in the OnBeforeClose() callback.

```cpp
void MyHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
  // Must be executed on the UI thread.
  REQUIRE_UI_THREAD();

  if (browser_id_ == browser->GetIdentifier()) {
    // Free the browser pointer so that the browser can be destroyed.
    browser_ = nullptr;
  }

  if (--browser_count_ == 0) {
    // All browser windows have closed. Quit the application message loop.
    CefQuitMessageLoop();
  }
}
```

See the cefclient application for complete working examples on each platform.

## Off-Screen Rendering

With off-screen rendering CEF does not create a native browser window. Instead, CEF provides the host application with invalidated regions and a pixel buffer and the host application notifies CEF of input events such as mouse, keyboard and focus. Off-screen rendering does not currently support accelerated compositing so performance may suffer as compared to a windowed browser. Off-screen browsers will receive the same notifications as windowed browsers including the life span notifications described in the previous section. To use off-screen rendering:

  1. Implement the [CefRenderHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRenderHandler.html) interface. All methods are required unless otherwise indicated.
  1. Call CefWindowInfo::SetAsWindowless() before passing the CefWindowInfo structure to CefBrowserHost::CreateBrowser(). If no parent window is passed to SetAsWindowless some functionality like context menus may not be available.
  1. The CefRenderHandler::GetViewRect() method will be called to retrieve the desired view rectangle.
  1. The CefRenderHandler::OnPaint() method will be called to provide invalid regions and the updated pixel buffer. The cefclient application draws the buffer using OpenGL but your application can use whatever technique you prefer.
  1. To resize the browser call CefBrowserHost::WasResized(). This will result in a call to GetViewRect() to retrieve the new size followed by a call to OnPaint().
  1. Call the CefBrowserHost::SendXXX() methods to notify the browser of mouse, keyboard and focus events.
  1. Call CefBrowserHost::CloseBrowser() to destroy browser.

Run cefclient with the "--off-screen-rendering-enabled" command-line flag for a working example.

# Posting Tasks

Tasks can be posted between the various threads in a single process using the CefPostTask family of methods (see the [include/cef\_task.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_task.h) header file for the complete list). The task will execute asynchronously on the message loop of the target thread.

CEF provides base::Bind[Once|Repeating] and base::[Once|Repeating]Callback templated callback classes for passing bound methods, objects and arguments to CefPostTask. For complete base::Bind and base::Callback usage information see the [Chromium documentation](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md). The [include/wrapper/cef\_closure\_task.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_closure_task.h) header provides helpers for converting a base::[Once|Repeating]Closure to a CefTask. For example:

```cpp
// Include the necessary headers.
#include "include/base/cef_callback.h"
#include "include/wrapper/cef_closure_task.h"

// To execute a bound function:

// Define a function.
void MyFunc(int arg) { /* do something with |arg| on the UI thread */ }

// Post a task that will execute MyFunc on the UI thread and pass an |arg|
// value of 5.
CefPostTask(TID_UI, base::BindOnce(&MyFunc, 5));

// To execute a bound method:

// Define a class.
class MyClass : public CefBaseRefCounted {
 public:
  MyClass() {}
  void MyMethod(int arg) { /* do something with |arg| on the UI thread */ }
 private:
  IMPLEMENT_REFCOUNTING(MyClass);
};

// Create an instance of MyClass.
CefRefPtr<MyClass> instance = new MyClass();

// Post a task that will execute MyClass::MyMethod on the UI thread and pass
// an |arg| value of 5. |instance| will be kept alive until after the task
// completes.
CefPostTask(TID_UI, base::BindOnce(&MyClass::MyMethod, instance, 5));
```

If the host application needs to keep a reference to a run loop it can use the CefTaskRunner class. For example, to get the task runner for the UI thread:

```cpp
CefRefPtr<CefTaskRunner> task_runner = CefTaskRunner::GetForThread(TID_UI);
```

# Inter-Process Communication (IPC)

Since CEF3 runs in multiple processes it is necessary to provide mechanisms for communicating between those processes. CefBrowser and CefFrame objects exist in both the browser and render processes which helps to facilitate this process. Each CefBrowser and CefFrame object also has a unique ID value associated with it that will match on both sides of the process boundary.

## Process Startup Messages

Startup data can be associated with a specific CefBrowser instance at creation time via the `CefRefPtr<CefDictionaryValue> extra_info` parameter to CefBrowserHost::CreateBrowser. That extra_info data will be delivered to every renderer process associated with that CefBrowser via the CefRenderProcessHandler::OnBrowserCreated callback. See the "Processes" section for more information about when and how a new renderer process will be spawned.

## Process Runtime Messages

Messages can be passed between processes at runtime using the [CefProcessMessage](https://cef-builds.spotifycdn.com/docs/stable.html?classCefProcessMessage.html) class. These messages are associated with a specific CefBrowser and CefFrame instance and sent using the CefFrame::SendProcessMessage() method. The process message should contain whatever state information is required via CefProcessMessage::GetArgumentList().

```cpp
// Create the message object.
CefRefPtr<CefProcessMessage> msg= CefProcessMessage::Create("my_message");

// Retrieve the argument list object.
CefRefPtr<CefListValue> args = msg>GetArgumentList();

// Populate the argument values.
args->SetString(0, "my string");
args->SetInt(0, 10);

// Send the process message to the main frame in the render process.
// Use PID_BROWSER instead when sending a message to the browser process.
browser->GetMainFrame()->SendProcessMessage(PID_RENDERER, msg);
```

A message sent from the browser process to the render process will arrive in CefRenderProcessHandler::OnProcessMessageReceived(). A message sent from the render process to the browser process will arrive in CefClient::OnProcessMessageReceived().

```cpp
bool MyHandler::OnProcessMessageReceived(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefProcessId source_process,
    CefRefPtr<CefProcessMessage> message) {
  // Check the message name.
  const std::string& message_name = message->GetName();
  if (message_name == "my_message") {
    // Handle the message here...
    return true;
  }
  return false;
}
```

## Asynchronous JavaScript Bindings

[Java Script Integration](javascript_integration.md) is implemented in the render process but frequently need to communicate with the browser process. The JavaScript APIs themselves should be designed to work asynchronously using [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures) and [promises](http://www.html5rocks.com/en/tutorials/es6/promises/).

### Generic Message Router

CEF provides a generic implementation for routing asynchronous messages between JavaScript running in the renderer process and C++ running in the browser process. An application interacts with the router by passing it data from standard CEF C++ callbacks (OnBeforeBrowse, OnProcessMessageRecieved, OnContextCreated, etc). The renderer-side router supports generic JavaScript callback registration and execution while the browser-side router supports application-specific logic via one or more application-provided Handler instances. See the [message_router example](https://github.com/chromiumembedded/cef-project/blob/master/examples/message_router/) for a stand-alone example application that demonstates CefMessageRouter usage. See [include/wrapper/cef\_message\_router.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_message_router.h) for complete usage documentation.

### Custom Implementation

A CEF-based application can also provide its own custom implementation of asynchronous JavaScript bindings. A simplistic implementation could work as follows:

1\. The JavaScript binding in the render process is passed a callback function.

```cpp
// In JavaScript register the callback function.
app.setMessageCallback('binding_test', function(name, args) {
  document.getElementById('result').value = "Response: "+args[0];
});
```

2\. The render process keeps a reference to the callback function.

```cpp
// Map of message callbacks.
typedef std::map<std::pair<std::string, int>,
                 std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value> > >
                 CallbackMap;
CallbackMap callback_map_;

// In the CefV8Handler::Execute implementation for "setMessageCallback".
if (arguments.size() == 2 && arguments[0]->IsString() &&
    arguments[1]->IsFunction()) {
  std::string message_name = arguments[0]->GetStringValue();
  CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
  int browser_id = context->GetBrowser()->GetIdentifier();
  callback_map_.insert(
      std::make_pair(std::make_pair(message_name, browser_id),
                     std::make_pair(context, arguments[1])));
}
```

3\. The render process sends an asynchronous IPC message to the browser process requesting that work be performed.

4\. The browser process receives the IPC message and performs the work.

5\. Upon completion of the work the browser process sends an asynchronous IPC message back to the render process with the result.

6\. The render process receives the IPC message and executes the callback function with the result.

```cpp
// Execute the registered JavaScript callback if any.
if (!callback_map_.empty()) {
  const CefString& message_name = message->GetName();
  CallbackMap::const_iterator it = callback_map_.find(
      std::make_pair(message_name.ToString(),
                     browser->GetIdentifier()));
  if (it != callback_map_.end()) {
    // Keep a local reference to the objects. The callback may remove itself
    // from the callback map.
    CefRefPtr<CefV8Context> context = it->second.first;
    CefRefPtr<CefV8Value> callback = it->second.second;

    // Enter the context.
    context->Enter();

    CefV8ValueList arguments;

    // First argument is the message name.
    arguments.push_back(CefV8Value::CreateString(message_name));

    // Second argument is the list of message arguments.
    CefRefPtr<CefListValue> list = message->GetArgumentList();
    CefRefPtr<CefV8Value> args = CefV8Value::CreateArray(list->GetSize());
    SetList(list, args);  // Helper function to convert CefListValue to CefV8Value.
    arguments.push_back(args);

    // Execute the callback.
    CefRefPtr<CefV8Value> retval = callback->ExecuteFunction(nullptr, arguments);
    if (retval.get()) {
      if (retval->IsBool())
        handled = retval->GetBoolValue();
    }

    // Exit the context.
    context->Exit();
  }
}
```

7\. Release any V8 references associated with the context in CefRenderProcessHandler::OnContextReleased().

```cpp
void MyHandler::OnContextReleased(CefRefPtr<CefBrowser> browser,
                                  CefRefPtr<CefFrame> frame,
                                  CefRefPtr<CefV8Context> context) {
  // Remove any JavaScript callbacks registered for the context that has been released.
  for (auto it = callback_map_.begin(); it != callback_map_.end();) {
    if (it->second.first->IsSame(context)) {
      it = callback_map_.erase(it);
    } else {
      ++it;
    }
  }
}
```

## Synchronous Requests

In rare cases it may be necessary to implement synchronous communication between the browser and render processes. This should be avoided whenever possible because it will negatively impact performance in the render process. However, if you must have synchronous communication consider using [synchronous XMLHttpRequests](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests) which will block the render process while awaiting handling in the browser process network layer. The browser process can handle the requests using a custom scheme handler or network interception. See the "Network Layer" section for more information.

# Network Layer

By default network requests in CEF3 will be handled in a manner transparent to the host application. For applications wishing for a closer relationship with the network layer CEF3 exposes a range of network-related functionalities.

Network-related callbacks can occur on different threads so make sure to pay attention to the documentation and properly protect your data members (see the "Threads" section for background).

## Custom Requests

The simplest way to load a URL in a browser frame is via the CefFrame::LoadURL() method.

```
browser->GetMainFrame()->LoadURL(some_url);
```

Applications wishing to send more complex requests containing custom request headers or upload data can use the CefFrame::LoadRequest() method. This method accepts a [CefRequest](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRequest.html) object as the single argument.

**WARNING: The LoadRequest method will fail with "bad IPC message" reason INVALID_INITIATOR_ORIGIN (213) unless you first navigate to the request origin (scheme + domain) using some other mechanism (LoadURL, link click, etc).**

```cpp
// Create a CefRequest object.
CefRefPtr<CefRequest> request = CefRequest::Create();

// Set the request URL.
request->SetURL(some_url);

// Set the request method. Supported methods include GET, POST, HEAD, DELETE and PUT.
request->SetMethod("POST");

// Optionally specify custom headers.
CefRequest::HeaderMap headerMap;
headerMap.insert(
    std::make_pair("X-My-Header", "My Header Value"));
request->SetHeaderMap(headerMap);

// Optionally specify upload content.
// The default "Content-Type" header value is "application/x-www-form-urlencoded".
// Set "Content-Type" via the HeaderMap if a different value is desired.
const std::string& upload_data = "arg1=val1&arg2=val2";
CefRefPtr<CefPostData> postData = CefPostData::Create();
CefRefPtr<CefPostDataElement> element = CefPostDataElement::Create();
element->SetToBytes(upload_data.size(), upload_data.c_str());
postData->AddElement(element);
request->SetPostData(postData);
```

### Browser-Independent Requests

Applications can send network requests via the [CefURLRequest](https://cef-builds.spotifycdn.com/docs/stable.html?classCefURLRequest.html) class. Implement the [CefURLRequestClient](https://cef-builds.spotifycdn.com/docs/stable.html?classCefURLRequestClient.html) interface to handle the resulting response.

  * Requests not associated with a particular CefBrowser/CefFrame can be sent via the CefURLRequest::Create method. These types of requests can only be used in the browser process.
  * Requests associated with a particular CefBrowser/CefFrame can be sent via the CefFrame::CreateURLRequest method. These types of requests can be used in both the browser and the renderer process.

See documentation on the above methods for additional usage restrictions.

Here is an example of CefURLRequest usage:

```
/* Detailed source-code truncated for AI context efficiency. */
```

To send the request:

```cpp
// Set up the CefRequest object.
CefRefPtr<CefRequest> request = CefRequest::Create();
// Populate |request| as shown above...

// Create the client instance.
CefRefPtr<MyRequestClient> client = new MyRequestClient();

// Start the request. MyRequestClient callbacks will be executed asynchronously.
CefRefPtr<CefURLRequest> url_request = CefURLRequest::Create(request, client.get(), nullptr);
// To cancel the request: url_request->Cancel();
```

Requests made with CefURLRequest can also specify custom behaviors via the CefRequest::SetFlags() method. Supported bit flags include:

  * **UR\_FLAG\_SKIP\_CACHE** If set the cache will be skipped when handling the request.
  * **UR\_FLAG\_ALLOW\_STORED\_CREDENTIALS** If set cookies may be sent with the request and saved from the response.
  * **UR\_FLAG\_REPORT\_UPLOAD\_PROGRESS** If set upload progress events will be generated when a request has a body.
  * **UR\_FLAG\_NO\_DOWNLOAD\_DATA** If set the CefURLRequestClient::OnDownloadData method will not be called.
  * **UR\_FLAG\_NO\_RETRY\_ON\_5XX** If set 5XX redirect errors will be propagated to the observer instead of automatically re-tried. This currently only applies for requests originated in the browser process.

See [cef\_urlrequest\_flags\_t](https://github.com/chromiumembedded/cef/blob/81e7748fb5008295c2a1f2d75b0f0c907c1fdfe8/include/internal/cef_types.h#L1243) for the complete list of supported flags.

For example, to skip the cache and not report download data:

```
request->SetFlags(UR_FLAG_SKIP_CACHE | UR_FLAG_NO_DOWNLOAD_DATA);
```

## Request Handling

CEF3 supports two approaches for handling network requests inside of an application. The scheme handler approach allows registration of a handler for requests targeting a particular origin (scheme + domain). The request interception approach allows handling of arbitrary requests at the application's discretion.

**WARNING: Use the HTTP scheme instead of a custom scheme to avoid a range of potential issues.**

If you choose to use a custom scheme (anything other than "HTTP", "HTTPS", etc) you must register it with CEF so that it will behave as expected. If you would like your custom scheme to behave similar to HTTP (support POST requests and enforce [HTTP access control (CORS)](https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS) restrictions) then it should be registered as a "standard" scheme. If you are planning to perform cross-origin requests to other schemes or send POST requests via XMLHttpRequest to your scheme handler then you should use the HTTP scheme instead of a custom scheme to avoid [potential issues](https://github.com/chromiumembedded/cef/issues/950). If you wish to use custom schemes the attributes are registered via the CefApp::OnRegisterCustomSchemes() callback which must be implemented in all processes.

```cpp
void MyApp::OnRegisterCustomSchemes(CefRefPtr<CefSchemeRegistrar> registrar) {
  // Register "client" as a standard scheme.
  int options = CEF_SCHEME_OPTION_STANDARD;
  registrar->AddCustomScheme("client", options);
}
```

See [cef\_scheme\_options\_t](https://github.com/chromiumembedded/cef/blob/81e7748fb5008295c2a1f2d75b0f0c907c1fdfe8/include/internal/cef_types.h#L2795) for the complete list of supported flags.

### Generic Resource Manager

CEF provides a generic implementation for managing resource requests from one or more data sources. This user registers handlers for different data sources, such as directories on disk, zip archives or custom implementations, and the manager handles the requests. An application interacts with the router by passing it data from standard CEF C++ callbacks (OnBeforeResourceLoad, GetResourceHandler). See the [resource_manager example](https://github.com/chromiumembedded/cef-project/blob/master/examples/resource_manager/) for a stand-alone example application that demonstates CefResourceManager usage. See [include/wrapper/cef\_resource\_manager.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_resource_manager.h) for complete usage documentation.

### Scheme Handler

A scheme handler is registered via the CefRegisterSchemeHandlerFactory() function. A good place to call this function is from CefBrowserProcessHandler::OnContextInitialized(). For example, you can register a handler for "client://myapp/" requests:

```
CefRegisterSchemeHandlerFactory("client", "myapp", new MySchemeHandlerFactory());
```

Handlers can be used with both built-in schemes (HTTP, HTTPS, etc) and custom schemes. When using a built-in scheme choose a domain name unique to your application (like "myapp" or "internal"). Implement the [CefSchemeHandlerFactory](https://cef-builds.spotifycdn.com/docs/stable.html?classCefSchemeHandlerFactory.html) and [CefResourceHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefResourceHandler.html) classes to handle the request and provide response data. If using custom schemes don't forget to implement the CefApp::OnRegisterCustomSchemes method as described above. See the [scheme_handler example](https://github.com/chromiumembedded/cef-project/blob/master/examples/scheme_handler/) for a stand-alone example application that demonstates CefSchemeHandlerFactory usage. See [include/cef\_scheme.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_scheme.h) for complete usage documentation.

If the response data is known at request time the [CefStreamResourceHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefStreamResourceHandler.html) class provides a convenient default implementation of CefResourceHandler.

```cpp
// CefStreamResourceHandler is part of the libcef_dll_wrapper project.
#include "include/wrapper/cef_stream_resource_handler.h"

const std::string& html_content = "<html><body>Hello!</body></html>";

// Create a stream reader for |html_content|.
CefRefPtr<CefStreamReader> stream =
    CefStreamReader::CreateForData(
        static_cast<void*>(const_cast<char*>(html_content.c_str())),
        html_content.size());

// Constructor for HTTP status code 200 and no custom response headers.
// There's also a version of the constructor for custom status code and response headers.
return new CefStreamResourceHandler("text/html", stream);
```

### Request Interception

The CefRequestHandler::GetResourceHandler() method supports the interception of arbitrary requests. It uses the same CefResourceHandler class as the scheme handler approach. If using custom schemes don't forget to implement the CefApp::OnRegisterCustomSchemes method as described above.

```cpp
CefRefPtr<CefResourceHandler> MyHandler::GetResourceHandler(
      CefRefPtr<CefBrowser> browser,
      CefRefPtr<CefFrame> frame,
      CefRefPtr<CefRequest> request) {
  // Evaluate |request| to determine proper handling...
  if (...)
    return new MyResourceHandler();

  // Return nullptr for default handling of the request.
  return nullptr;
}
```

### Response Filtering

The CefRequestHandler::GetResourceResponseFilter() method supports filtering of request response data. See [cefclient/browser/response\_filter\_test.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/browser/response_filter_test.cc) (accessible via the Tests menu > Other Tests > Response Filtering from inside the cefclient sample application) for a working example.

## Other Callbacks

The [CefRequestHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRequestHandler.html) interface provides callbacks for various network-related events incuding authentication, cookie handling, external protocol handling, certificate errors and so on.

## Proxy Resolution

Proxy settings are configured in CEF3 using the same command-line flags as Google Chrome.

```
--proxy-server=host:port
      Specify the HTTP/SOCKS4/SOCKS5 proxy server to use for requests. An individual proxy
      server is specified using the format:

        [<proxy-scheme>://]<proxy-host>[:<proxy-port>]

      Where <proxy-scheme> is the protocol of the proxy server, and is one of:

        "http", "socks", "socks4", "socks5".

      If the <proxy-scheme> is omitted, it defaults to "http". Also note that "socks" is equivalent to
      "socks5".

      Examples:

        --proxy-server="foopy:99"
            Use the HTTP proxy "foopy:99" to load all URLs.

        --proxy-server="socks://foobar:1080"
            Use the SOCKS v5 proxy "foobar:1080" to load all URLs.

        --proxy-server="sock4://foobar:1080"
            Use the SOCKS v4 proxy "foobar:1080" to load all URLs.

        --proxy-server="socks5://foobar:66"
            Use the SOCKS v5 proxy "foobar:66" to load all URLs.

      It is also possible to specify a separate proxy server for different URL types, by prefixing
      the proxy server specifier with a URL specifier:

      Example:

        --proxy-server="https=proxy1:80;http=socks4://baz:1080"
            Load https://* URLs using the HTTP proxy "proxy1:80". And load http://*
            URLs using the SOCKS v4 proxy "baz:1080".

--no-proxy-server
      Disables the proxy server.

--proxy-auto-detect
      Autodetect  proxy  configuration.

--proxy-pac-url=URL
      Specify proxy autoconfiguration URL.
```

If the proxy requires authentication the CefRequestHandler::GetAuthCredentials() callback will be executed with an `isProxy` value of true to retrieve the username and password.

```cpp
bool MyHandler::GetAuthCredentials(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    bool isProxy,
    const CefString& host,
    int port,
    const CefString& realm,
    const CefString& scheme,
    CefRefPtr<CefAuthCallback> callback) {
  if (isProxy) {
    // Provide credentials for the proxy server connection.
    callback->Continue("myuser", "mypass");
    return true;
  }
  return false;
}
```

Web content loading during application startup can be delayed due to network proxy resolution (for example, if "Automatically detect proxy settings" is checked on Windows). For best user experience consider designing your application to first show a static splash page and then redirect to the actual website using [meta refresh](http://en.wikipedia.org/wiki/Meta_refresh) -- the redirect will be blocked until proxy resolution completes. For testing purposes proxy resolution can be disabled using the "--no-proxy-server" command-line flag. Proxy resolution delays can also be duplicated in Google Chrome by running "chrome --url=..." from the command line.

---

### Hands On Tutorial (`docs/hands_on_tutorial.md`)

This page provides a hands-on tutorial for building a CEF application by progressively modifying the cefsimple example.

**Contents**

- [Introduction](#introduction)
  - [CEF Quick Concepts](#cef-quick-concepts)
- [Step 0: Setup and Verify](#step-0-setup-and-verify)
  - [Download and Build cefsimple](#download-and-build-cefsimple)
  - [Understanding cefsimple Structure](#understanding-cefsimple-structure)
- [Step 1: Simplify to Absolute Minimum](#step-1-simplify-to-absolute-minimum)
  - [What We're Removing](#what-were-removing)
  - [Architecture Overview](#architecture-overview)
  - [Modified Files](#modified-files)
    - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh)
    - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc)
    - [tests/cefsimple/simple_app.h](#testscefsimplesimple_apph)
    - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc)
    - [Delete Platform-Specific Handler Files](#delete-platform-specific-handler-files)
    - [Update CMakeLists.txt](#update-cmakeliststxt)
    - [Keep Unchanged](#keep-unchanged)
  - [Limitations of This Simplified Version](#limitations-of-this-simplified-version)
  - [Build and Run](#build-and-run)
  - [What's Happening](#whats-happening)
  - [Common Issues](#common-issues)
- [Step 2: Custom URL from Code](#step-2-custom-url-from-code)
  - [What We're Adding](#what-were-adding)
  - [Modified Files](#modified-files)
    - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc)
  - [Build and Run](#build-and-run)
  - [What's Happening](#whats-happening)
- [Step 3: Command-Line URL Support](#step-3-command-line-url-support)
  - [What We're Adding](#what-were-adding)
  - [Modified Files](#modified-files)
    - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc)
  - [Build and Run](#build-and-run)
  - [What's Happening](#whats-happening)
- [Step 4: Window Title Updates](#step-4-window-title-updates)
  - [What We're Adding](#what-were-adding)
  - [Modified Files](#modified-files)
    - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh)
    - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc)
  - [Build and Run](#build-and-run)
  - [What's Happening](#whats-happening)
- [Step 5: JavaScript Execution](#step-5-javascript-execution)
  - [What We're Adding](#what-were-adding)
  - [Modified Files](#modified-files)
    - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh)
    - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc)
  - [Build and Run](#build-and-run)
  - [What's Happening](#whats-happening)
- [Step 6: JavaScript-to-C++ Communication](#step-6-javascript-to-c-communication)
  - [What We're Adding](#what-were-adding)
  - [Modified Files](#modified-files)
    - [tests/cefsimple/simple_app.h](#testscefsimplesimple_apph)
    - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc)
    - [Platform Entry Points](#platform-entry-points)
      - [tests/cefsimple/cefsimple_linux.cc](#testscefsimplecefsimple_linuxcc)
      - [tests/cefsimple/cefsimple_win.cc](#testscefsimplecefsimple_wincc)
      - [tests/cefsimple/process_helper_mac.cc](#testscefsimpleprocess_helper_maccc)
      - [tests/cefsimple/CMakeLists.txt (macOS only)](#testscefsimplecmakeliststxt-macos-only)
    - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh)
    - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc)
  - [Build and Run](#build-and-run)
  - [What's Happening](#whats-happening)
- [Step 7: Multiple Browser Support](#step-7-multiple-browser-support)
  - [What We're Adding](#what-were-adding)
  - [Why This Matters](#why-this-matters)
  - [Modified Files](#modified-files)
    - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh)
    - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc)
  - [Build and Run](#build-and-run)
  - [What's Happening](#whats-happening)
- [Step 8: Views Styling of Popup Browsers](#step-8-views-styling-of-popup-browsers)
  - [What We're Adding](#what-were-adding)
  - [Why This Matters](#why-this-matters)
  - [Modified Files](#modified-files)
    - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc)
  - [Build and Run](#build-and-run)
  - [What's Happening](#whats-happening)
- [Next Steps](#next-steps)
  - [Explore More Features](#explore-more-features)
  - [Learn Advanced Topics](#learn-advanced-topics)
  - [Using the C API](#using-the-c-api)
  - [Using Claude Code for Implementation](#using-claude-code-for-implementation)

---

# Introduction

This tutorial teaches CEF development by **modifying the cefsimple example** step-by-step. You'll start with a working application and progressively add features, learning CEF concepts along the way.

**Who is this for?**

- Developers new to CEF who want hands-on learning
- C++ developers with basic knowledge (classes, pointers, inheritance)
- Those who prefer learning by doing rather than reading reference documentation
- Anyone who wants to understand CEF architecture through practice

**Why start from cefsimple?**

- ✅ CMake already configured correctly
- ✅ Resources (`.pak` files, frameworks) already in the right place
- ✅ macOS app bundle structure already set up
- ✅ Platform-specific entry points already working
- ✅ You can verify your build environment works before making changes

**Prerequisites:**

- CEF binary distribution for your platform ([download here](https://cef-builds.spotifycdn.com/index.html))
- C++ compiler:
    - Windows: Visual Studio 2022
    - macOS: Xcode with command-line tools
    - Linux: GCC/Clang, build-essential, and libgtk-3-dev packages
- CMake 3.19+

**What you'll build:**

Starting from cefsimple, you'll progressively add features to create a custom browser with JavaScript integration and popup window customization.

**Using the C API?** This tutorial uses the C++ API. For pure C implementation, see [cefsimple_capi](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/) and [Using The CAPI](using_the_capi.md).

## CEF Quick Concepts

Before diving into code, here are the key CEF concepts you'll encounter:

**Multi-process architecture:** CEF runs multiple processes for security and stability:

- **Browser process** - Main process, manages UI and coordinates other processes
- **Render processes** - Isolated processes for web content (one per site)
- **GPU process** - Hardware-accelerated graphics
- **Other processes** - Network service, audio service, etc.

**Reference counting:** CEF objects use reference counting for memory management:

- `CefRefPtr<T>` - Smart pointer that automatically manages reference counts
- `IMPLEMENT_REFCOUNTING` macro - Adds thread-safe reference counting to your classes
- Objects are deleted when their reference count reaches zero

**Threading:** CEF callbacks run on specific threads:

- **UI thread** - Browser process main thread (most callbacks run here)
- **IO thread** - Network operations
- **Renderer thread** - JavaScript execution (in render process)
- Use `CEF_REQUIRE_UI_THREAD()`, `CEF_REQUIRE_RENDERER_THREAD()`, etc. to assert correct thread usage

**Browser styles:**

- **Chrome style** - Full Chrome UI with tabs, address bar, etc. (default in unmodified cefsimple)
- **Alloy style** - Lightweight mode, you control all UI (we switch to this in Step 1)
- Unmodified cefsimple supports both styles: use `--use-alloy-style` command-line flag for Alloy
- Set via `GetBrowserRuntimeStyle()` and `GetWindowRuntimeStyle()`

**Views framework:** Cross-platform UI system:

- `CefWindow` - Top-level window
- `CefBrowserView` - Embeds the browser in a view
- Delegates (`CefWindowDelegate`, `CefBrowserViewDelegate`) - Control window/browser behavior
- Alternative: Platform-native UI or off-screen rendering (OSR)

**For deeper coverage** of CEF architecture and concepts, see [Tutorial.md](tutorial.md).

# Step 0: Setup and Verify

## Download and Build cefsimple

1. **Download CEF binary distribution:**

    Visit [https://cef-builds.spotifycdn.com/index.html](https://cef-builds.spotifycdn.com/index.html) and download the appropriate binary distribution for your platform (e.g., `cef_binary_<version>_windows64.tar.bz2`).

2. **Extract and enter the directory:**

    ```bash
    tar -xjf cef_binary_<version>_<platform>.tar.bz2
    cd cef_binary_<version>_<platform>
```

3. **Build cefsimple as-is:**

    **Windows:**
    ```bash
    # Build with sandbox disabled for simplicity
    cmake -B build -G "Visual Studio 17 2022" -A x64 -DUSE_SANDBOX=OFF
    cmake --build build --config Release --target cefsimple
    build\tests\cefsimple\Release\cefsimple.exe
```

    **Note:** This tutorial builds with sandbox disabled (`-DUSE_SANDBOX=OFF`) for simplicity. For production applications, you should enable the sandbox using the [bootstrap.exe approach](sandbox_setup.md#windows). The sandbox provides important security isolation for renderer processes.

    **Linux:**
    ```bash
    cmake -B build
    cmake --build build --target cefsimple
    build/tests/cefsimple/cefsimple
```

    **macOS:**
    ```bash
    cmake -B build -G Xcode
    cmake --build build --config Release --target cefsimple
    open build/tests/cefsimple/Release/cefsimple.app
```

    **Using an IDE (optional):**

    Instead of building from the command line, you can open the generated project in your IDE:

    - **Windows**: Open `build/cef.sln` in Visual Studio 2022
    - **macOS**: Open `build/cef.xcodeproj` in Xcode
    - **Linux**: Open the `build` directory in CLion or another CMake-supporting IDE

4. **Verify it works:**

    - You should see a window displaying google.com
    - Window title should update with the page title
    - Closing the window should exit the app cleanly

**If this works, your environment is set up correctly!** Now we can start learning CEF by modifying the code.

## Understanding cefsimple Structure

```text
tests/cefsimple/
├── simple_app.h                # Application handler (process-level)
├── simple_app.cc               # Browser creation logic
├── simple_handler.h            # Browser handler interface
├── simple_handler.cc           # Browser-level event handling
├── simple_handler_win.cc       # Windows-specific (window title)
├── simple_handler_linux.cc     # Linux-specific (window title)
├── simple_handler_mac.mm       # macOS-specific (window title)
├── cefsimple_win.cc            # Windows entry point
├── cefsimple_linux.cc          # Linux entry point
├── cefsimple_mac.mm            # macOS browser process entry point
└── process_helper_mac.cc       # macOS helper process entry point
```

**Cross-platform code:** `simple_app.*`, `simple_handler.h/cc` work identically on all platforms.

**Platform-specific code:** Entry points and window title updates for platform-specific implementations.

# Step 1: Simplify to Absolute Minimum

**Goal:** Strip cefsimple down to the bare minimum (~150 lines total) to understand the essential parts.

## What We're Removing

cefsimple has features we don't need yet:

- ❌ Command-line URL argument handling
- ❌ Window title updates
- ❌ Error page handling
- ❌ Multiple browser tracking

Let's remove these to see the core clearly.

## Architecture Overview

Before we dive into the code, here's what each piece does:

**SimpleApp** - Application-level handler

- Creates the browser and window when CEF is initialized
- Uses the Views framework (cross-platform UI)

**SimpleHandler** - Browser-level event handler

- Handles browser lifecycle events (created, closed)
- Implements singleton pattern (global instance accessed by platform entry points)
- Quits the app when the browser closes

**Views Framework Delegates** (in simple_app.cc)

- `SimpleWindowDelegate` - Controls window size, close behavior, runtime style
- `SimpleBrowserViewDelegate` - Specifies Alloy browser style

**Platform Entry Point Methods**

- `GetInstance()` - Returns the singleton instance (fully functional)
- `CloseAllBrowsers()`, `IsClosing()` - Empty stubs for now (implemented in Step 7 for multi-browser support)
- `ShowMainWindow()` - Called on macOS when user clicks dock icon. Empty stub in this tutorial (a proper implementation would show/activate the main window)

Now let's see the actual code:

## Modified Files

### tests/cefsimple/simple_handler.h

This is the browser-level event handler. Note the singleton pattern (`GetInstance()`) and stub methods for platform entry points.

**Replace the entire file with:**

```cpp
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_

#include "include/cef_client.h"

// Simple browser event handler
// Inherits from CefClient (main handler interface) and CefLifeSpanHandler
// (lifecycle events). This allows one class to handle multiple callback types.
class SimpleHandler : public CefClient, public CefLifeSpanHandler {
 public:
  SimpleHandler();
  ~SimpleHandler() override;

  // Provide access to the single global instance of this object.
  // Used by platform entry points (cefsimple_mac.mm, etc.)
  static SimpleHandler* GetInstance();

  // CefClient methods:
  CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }

  // CefLifeSpanHandler methods:
  void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;

  // Request that all existing browser windows close.
  // Used by platform entry points (cefsimple_mac.mm, etc.)
  void CloseAllBrowsers(bool force_close);

  // Always returns false - stub for platform entry points
  bool IsClosing() const { return false; }

  void ShowMainWindow();

 private:
  // Provides thread-safe reference counting (CefRefPtr).
  IMPLEMENT_REFCOUNTING(SimpleHandler);
  // Prevents copying (CEF objects shouldn't be copied).
  DISALLOW_COPY_AND_ASSIGN(SimpleHandler);
};

#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
```

### tests/cefsimple/simple_handler.cc

Implementation of SimpleHandler. The key method is `OnBeforeClose()` which quits the app when the browser closes.

**Replace the entire file with:**

```cpp
#include "tests/cefsimple/simple_handler.h"

#include "include/cef_app.h"
#include "include/wrapper/cef_helpers.h"

namespace {
// Anonymous namespace - variables here are only visible in this file
SimpleHandler* g_instance = nullptr;

}  // namespace

SimpleHandler::SimpleHandler() {
  DCHECK(!g_instance);  // Debug assertion - crashes if instance already exists
  g_instance = this;
}

SimpleHandler::~SimpleHandler() {
  g_instance = nullptr;
}

// static
SimpleHandler* SimpleHandler::GetInstance() {
  return g_instance;
}

void SimpleHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // Browser closed - quit the application
  // This simplified version only supports a single browser
  CefQuitMessageLoop();
}

void SimpleHandler::CloseAllBrowsers(bool force_close) {
  // Empty stub - required by platform entry points but not used
  // in this simplified Views-based version
}

void SimpleHandler::ShowMainWindow() {
  // Empty stub. A proper implementation would show/activate the main window.
  // Called on macOS when user clicks the dock icon while app is running.
}
```

### tests/cefsimple/simple_app.h

Application-level handler that receives callbacks when CEF is initialized. Declares `OnContextInitialized()` where we create the browser.

**Replace the entire file with:**

```cpp
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_

#include "include/cef_app.h"

// Implement application-level callbacks for the browser process.
class SimpleApp : public CefApp, public CefBrowserProcessHandler {
 public:
  SimpleApp();

  // CefApp methods:
  CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override {
    return this;
  }

  // CefBrowserProcessHandler methods:
  void OnContextInitialized() override;

 private:
  IMPLEMENT_REFCOUNTING(SimpleApp);
  DISALLOW_COPY_AND_ASSIGN(SimpleApp);
};

#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
```

### tests/cefsimple/simple_app.cc

Implementation of SimpleApp. Creates the browser and window using Views framework. Contains inline delegate classes that control window and browser behavior.

**Replace the entire file with:**

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Delete Platform-Specific Handler Files

Since we removed window title updates, delete these files:

- `tests/cefsimple/simple_handler_win.cc`
- `tests/cefsimple/simple_handler_linux.cc`
- `tests/cefsimple/simple_handler_mac.mm`

### Update CMakeLists.txt

`CMakeLists.txt` tells CMake which source files to compile. Since we deleted the platform-specific handler files, we need to remove them from the build configuration.

Update `tests/cefsimple/CMakeLists.txt` to remove references to the deleted files:

**Find these lines:**

```cmake
set(CEFSIMPLE_SRCS_LINUX
  cefsimple_linux.cc
  simple_handler_linux.cc
  )
set(CEFSIMPLE_SRCS_MAC
  cefsimple_mac.mm
  simple_handler_mac.mm
  )
set(CEFSIMPLE_SRCS_WINDOWS
  cefsimple_win.cc
  resource.h
  simple_handler_win.cc
  )
```

**Replace with:**

```cmake
set(CEFSIMPLE_SRCS_LINUX
  cefsimple_linux.cc
  )
set(CEFSIMPLE_SRCS_MAC
  cefsimple_mac.mm
  )
set(CEFSIMPLE_SRCS_WINDOWS
  cefsimple_win.cc
  resource.h
  )
```

This removes the references to `simple_handler_linux.cc`, `simple_handler_mac.mm`, and `simple_handler_win.cc` that we deleted.

### Keep Unchanged

**Don't modify these files** - they contain platform-specific entry point code that's already correct:

- [cefsimple_win.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_win.cc) - Windows entry point (modified in Step 6)
- [cefsimple_linux.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_linux.cc) - Linux entry point (modified in Step 6)
- [cefsimple_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_mac.mm) - macOS browser process entry point
- [process_helper_mac.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/process_helper_mac.cc) - macOS helper process entry point (modified in Step 6)

## Limitations of This Simplified Version

This simplified code has the following limitations:

- **Alloy style only**: Hardcoded to `CEF_RUNTIME_STYLE_ALLOY` in both `SimpleWindowDelegate` and `SimpleBrowserViewDelegate`. The original cefsimple supports both Chrome and Alloy styles via command-line flag.
- **Single browser only**: The app exits immediately when the browser window closes. Multi-browser support requires tracking browser instances (added in Step 7).
- **No window title updates**: We removed the handlers that update window titles based on page titles (added back in Step 4).
- **No command-line URL support**: The URL is hardcoded to "https://www.google.com" (added in Step 3).
- **Quit menu doesn't work**: On macOS, the Quit option in the application menu doesn't work (the stub `CloseAllBrowsers()` implementation does nothing). You must close the window to quit the app. (Fixed in Step 7)
- **Dock icon doesn't restore window**: On macOS, clicking the dock icon when the app is running doesn't restore the window (the stub `ShowMainWindow()` implementation does nothing). This remains a stub throughout the tutorial.
- **Empty stub methods**: `CloseAllBrowsers()` and `IsClosing()` are empty stubs (implemented in Step 7 for multi-browser support). `ShowMainWindow()` remains a stub throughout (a proper implementation would show/activate the main window on macOS).

These limitations are intentional to keep the code minimal for learning. We'll add features back in subsequent steps.

## Build and Run

```bash
# Rebuild using the same commands as Step 0

# Windows
cmake --build build --config Release --target cefsimple

# Linux
cmake --build build --target cefsimple

# macOS
cmake --build build --config Release --target cefsimple
```

**Run:** See Step 0 for platform-specific run instructions.

You should see a window open with google.com. **Note:** The window title won't update with the page title anymore (we removed that feature to simplify), but otherwise the app works the same as the original. Now you understand every line of code!

## What's Happening

**Three key pieces:**

1. **SimpleApp** (application-level handler)
    - Inherits from `CefApp` and `CefBrowserProcessHandler`
    - `OnContextInitialized()` - Called when CEF is ready to create browsers
    - Creates the browser and window using Views framework

2. **SimpleHandler** (browser-level event handler)
    - Inherits from `CefClient` and `CefLifeSpanHandler`
    - `GetLifeSpanHandler()` - Returns this handler for lifecycle events
    - `OnBeforeClose()` - Called when browser is closing, quits the app

3. **Views Framework Delegates**
    - `SimpleWindowDelegate` - Controls window size, close behavior, runtime style
    - `SimpleBrowserViewDelegate` - Specifies Alloy browser style
    - Both are **cross-platform** - same code works on Windows, Linux, macOS

**Why Alloy style?** Simpler than Chrome style - you control the UI completely. We explicitly set `CEF_RUNTIME_STYLE_ALLOY` in both delegates.

**Entry points:** Platform-specific files (`cefsimple_*.cc/mm`) handle:

- CEF initialization (`CefInitialize`)
- Message loop (`CefRunMessageLoop`)
- Shutdown (`CefShutdown`)
- macOS-specific: Framework loading, NSApplication setup

**Program Flow:** Here's the complete execution sequence:

1. **main()** (in entry point file) - Program starts
2. **CefInitialize()** - Initializes CEF with SimpleApp instance
3. **SimpleApp::OnContextInitialized()** - CEF ready, creates browser:
    - Creates SimpleHandler instance
    - Creates CefBrowserView with URL
    - Creates CefWindow with SimpleWindowDelegate
4. **CefRunMessageLoop()** - Enters message loop, processes events
5. **User closes window** → SimpleWindowDelegate::CanClose() → TryCloseBrowser()
6. **SimpleHandler::OnBeforeClose()** - Called when browser is closing
    - Calls CefQuitMessageLoop() to exit the message loop
7. **CefShutdown()** - Cleanup and shutdown CEF
8. **main() exits** - Program terminates

## Common Issues

- **Build errors about missing files** - Make sure you:
    1. Deleted the three platform handler files (`simple_handler_*.cc/mm`)
    2. Updated `CMakeLists.txt` to remove references to those files (see instructions above)

# Step 2: Custom URL from Code

**Goal:** Load different URLs by modifying the code (not command-line yet).

## What We're Adding

Just change one line to demonstrate how browser creation works.

## Modified Files

### tests/cefsimple/simple_app.cc

**In `OnContextInitialized()`, replace the URL:**

From: `"https://www.google.com"`
To: `"https://www.wikipedia.org"`

## Build and Run

```bash
# Rebuild using the same commands as Step 0

# Windows
cmake --build build --config Release --target cefsimple

# Linux
cmake --build build --target cefsimple

# macOS
cmake --build build --config Release --target cefsimple
```

**Run:** See Step 0 for platform-specific run instructions.

Now it loads Wikipedia instead! This shows that the URL is set when creating the `CefBrowserView`.

**Try these:**

- `file:///path/to/local.html` - Local files (use absolute path)
- `data:text/html,<h1>Hello CEF!</h1>` - Inline HTML
- Any HTTPS URL

## What's Happening

The second parameter to `CefBrowserView::CreateBrowserView` is the initial URL. The browser navigates to this URL immediately after creation.

# Step 3: Command-Line URL Support

**Goal:** Pass custom URLs via command-line: `cefsimple --url=https://example.com`

## What We're Adding

Read the command-line and use it to set the URL.

## Modified Files

### tests/cefsimple/simple_app.cc

**Add at the top:**

```cpp
#include "include/cef_command_line.h"
```

**Replace `OnContextInitialized` with:**

```cpp
void SimpleApp::OnContextInitialized() {
  CEF_REQUIRE_UI_THREAD();

  // Get command-line arguments
  CefRefPtr<CefCommandLine> command_line =
      CefCommandLine::GetGlobalCommandLine();

  // Check for --url= parameter
  std::string url = command_line->GetSwitchValue("url");
  if (url.empty()) {
    url = "https://www.google.com";  // Default URL
  }

  CefRefPtr<SimpleHandler> handler(new SimpleHandler());
  CefBrowserSettings browser_settings;

  CefRefPtr<CefBrowserView> browser_view = CefBrowserView::CreateBrowserView(
      handler, url, browser_settings, nullptr, nullptr,
      new SimpleBrowserViewDelegate());

  CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view));
}
```

## Build and Run

```bash
# Rebuild using the same commands as Step 0

# Windows
cmake --build build --config Release --target cefsimple

# Linux
cmake --build build --target cefsimple

# macOS
cmake --build build --config Release --target cefsimple
```

**Run with custom URL:**

```bash
# Windows
build\tests\cefsimple\Release\cefsimple.exe --url=https://github.com

# Linux
build/tests/cefsimple/cefsimple --url=https://github.com

# macOS
open build/tests/cefsimple/Release/cefsimple.app --args --url=https://github.com
```

## What's Happening

**New concepts:**

- `CefCommandLine::GetGlobalCommandLine()` - Access command-line arguments parsed by CEF
- `GetSwitchValue("url")` - Read the value of `--url=` parameter
- CEF automatically parses command-line in the entry point before calling `OnContextInitialized`

**Try it:**

```bash
# Load local file
cefsimple --url=file:///home/user/test.html

# Load data URL (note the quotes to escape shell characters)
cefsimple --url="data:text/html,<h1>Hello!</h1>"
```

# Step 4: Window Title Updates

**Goal:** Update window title to match the page title as it loads.

## What We're Adding

- Display handler to receive title change events
- Get window from browser to update its title

## Modified Files

### tests/cefsimple/simple_handler.h

**Update to add display handler:**

```cpp
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_

#include "include/cef_client.h"

class SimpleHandler : public CefClient,
                      // NEW: Add display handler for title change events
                      public CefDisplayHandler,
                      public CefLifeSpanHandler {
 public:
  SimpleHandler();
  ~SimpleHandler() override;

  static SimpleHandler* GetInstance();

  // CefClient methods:
  // NEW: Return display handler
  CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; }
  CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }

  // CefDisplayHandler methods:
  // NEW: Handle page title changes
  void OnTitleChange(CefRefPtr<CefBrowser> browser,
                     const CefString& title) override;

  // CefLifeSpanHandler methods:
  void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;

  void CloseAllBrowsers(bool force_close);
  bool IsClosing() const { return false; }
  void ShowMainWindow();

 private:
  IMPLEMENT_REFCOUNTING(SimpleHandler);
  DISALLOW_COPY_AND_ASSIGN(SimpleHandler);
};

#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
```

### tests/cefsimple/simple_handler.cc

**Add new includes at the top:**

```cpp
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
```

**Add the OnTitleChange implementation** (after the existing methods, before `OnBeforeClose()`):

```cpp
void SimpleHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
                                   const CefString& title) {
  CEF_REQUIRE_UI_THREAD();

  // Get the browser view from the browser
  CefRefPtr<CefBrowserView> browser_view =
      CefBrowserView::GetForBrowser(browser);
  if (browser_view) {
    // Get the window and update its title
    CefRefPtr<CefWindow> window = browser_view->GetWindow();
    if (window) {
      window->SetTitle(title);
    }
  }
}
```

**Note:** `OnBeforeClose()` and other methods from Step 1 remain unchanged.

## Build and Run

```bash
# Rebuild using the same commands as Step 0

# Windows
cmake --build build --config Release --target cefsimple

# Linux
cmake --build build --target cefsimple

# macOS
cmake --build build --config Release --target cefsimple
```

**Run:** See Step 0 for platform-specific run instructions.

Now the window title updates to match the page title as you navigate!

## What's Happening

**New concepts:**

- `CefDisplayHandler::OnTitleChange()` - Called when the page title changes
- `CefBrowserView::GetForBrowser()` - Get the browser view from a browser instance
- `CefBrowserView::GetWindow()` - Get the window containing the browser view
- `CefWindow::SetTitle()` - Update the window title

**Flow:**

1. Page loads or navigates → `OnTitleChange()` called with new title
2. We get the browser view from the browser parameter
3. We get the window from the browser view and update its title

# Step 5: JavaScript Execution

**Goal:** Execute JavaScript code in the page from C++.

## What We're Adding

- Load handler to know when page is ready
- Execute JavaScript after page loads

## Modified Files

### tests/cefsimple/simple_handler.h

**Add load handler:**

```cpp
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_

#include "include/cef_client.h"

class SimpleHandler : public CefClient,
                      public CefDisplayHandler,
                      public CefLifeSpanHandler,
                      // NEW: Add load handler for page load events
                      public CefLoadHandler {
 public:
  SimpleHandler();
  ~SimpleHandler() override;

  static SimpleHandler* GetInstance();

  // CefClient methods:
  CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; }
  CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }
  // NEW: Return load handler
  CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }

  // CefDisplayHandler methods:
  void OnTitleChange(CefRefPtr<CefBrowser> browser,
                     const CefString& title) override;

  // CefLifeSpanHandler methods:
  void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;

  // CefLoadHandler methods:
  // NEW: Handle page load completion
  void OnLoadEnd(CefRefPtr<CefBrowser> browser,
                 CefRefPtr<CefFrame> frame,
                 int httpStatusCode) override;

  void CloseAllBrowsers(bool force_close);
  bool IsClosing() const { return false; }
  void ShowMainWindow();

 private:
  IMPLEMENT_REFCOUNTING(SimpleHandler);
  DISALLOW_COPY_AND_ASSIGN(SimpleHandler);
};

#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
```

### tests/cefsimple/simple_handler.cc

**Add the OnLoadEnd implementation** (after `OnTitleChange()`, before `OnBeforeClose()`):

```cpp
void SimpleHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
                               CefRefPtr<CefFrame> frame,
                               int httpStatusCode) {
  CEF_REQUIRE_UI_THREAD();

  // Only execute on the main frame
  if (!frame->IsMain()) {
    return;
  }

  // Execute JavaScript to change the page background color
  frame->ExecuteJavaScript(
      "document.body.style.backgroundColor = 'lightblue';",
      frame->GetURL(), 0);
}
```

## Build and Run

```bash
# Rebuild using the same commands as Step 0

# Windows
cmake --build build --config Release --target cefsimple

# Linux
cmake --build build --target cefsimple

# macOS
cmake --build build --config Release --target cefsimple
```

**Run:** See Step 0 for platform-specific run instructions.

Now when pages load, the background turns light blue!

## What's Happening

**New concepts:**

- `CefLoadHandler::OnLoadEnd()` - Called when a frame finishes loading
- `CefFrame::IsMain()` - Check if this is the main frame (not an iframe)
- `CefFrame::ExecuteJavaScript()` - Execute arbitrary JavaScript code
- Parameters: JavaScript code, source URL (for debugging), start line number

**Try modifying the JavaScript:**

```cpp
// Alert box
frame->ExecuteJavaScript("alert('Hello from C++!');", frame->GetURL(), 0);

// DOM manipulation
frame->ExecuteJavaScript(
    "var h1 = document.createElement('h1');"
    "h1.textContent = 'Added by CEF!';"
    "document.body.insertBefore(h1, document.body.firstChild);",
    frame->GetURL(), 0);

// Console log
frame->ExecuteJavaScript("console.log('CEF executed this');",
                         frame->GetURL(), 0);
```

**Important notes:**

- JavaScript executes asynchronously
- `ExecuteJavaScript()` doesn't return the result directly
- To get results, use `EvaluateJavaScript()` (not shown) or process messages (next step)

# Step 6: JavaScript-to-C++ Communication

**Goal:** Call C++ functions from JavaScript code in the page.

## What We're Adding

- Process message handler to receive messages from the renderer process
- V8 context handler to register JavaScript functions
- Bidirectional communication between C++ and JavaScript

This requires implementing both browser process and renderer process handlers.

## Modified Files

### tests/cefsimple/simple_app.h

**Update to add renderer process handler:**

```cpp
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_

#include "include/cef_app.h"

class SimpleApp : public CefApp,
                  public CefBrowserProcessHandler,
                  // NEW: Add renderer process handler for JavaScript integration
                  public CefRenderProcessHandler {
 public:
  SimpleApp();

  // CefApp methods:
  CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override {
    return this;
  }
  // NEW: Return renderer process handler
  CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override {
    return this;
  }

  // CefBrowserProcessHandler methods:
  void OnContextInitialized() override;

  // NEW: CefRenderProcessHandler methods for JavaScript integration
  // NEW: Called when the JavaScript context is created in the renderer process
  void OnContextCreated(CefRefPtr<CefBrowser> browser,
                        CefRefPtr<CefFrame> frame,
                        CefRefPtr<CefV8Context> context) override;

 private:
  IMPLEMENT_REFCOUNTING(SimpleApp);
  DISALLOW_COPY_AND_ASSIGN(SimpleApp);
};

#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
```

### tests/cefsimple/simple_app.cc

**Add new includes at the top** (after the existing includes):

```cpp
#include "include/cef_v8.h"
```

**Add V8 handler class in the anonymous namespace** (add after the includes, before the existing SimpleWindowDelegate and SimpleBrowserViewDelegate classes which remain unchanged):

```cpp
// V8 handler to handle JavaScript function calls in the renderer process
class MyV8Handler : public CefV8Handler {
 public:
  MyV8Handler() = default;

  bool Execute(const CefString& name,
               CefRefPtr<CefV8Value> object,
               const CefV8ValueList& arguments,
               CefRefPtr<CefV8Value>& retval,
               CefString& exception) override {
    if (name == "sayHello") {
      // Get the argument
      if (arguments.size() == 1 && arguments[0]->IsString()) {
        CefString message = arguments[0]->GetStringValue();

        // Send message to browser process
        CefRefPtr<CefProcessMessage> msg =
            CefProcessMessage::Create("greeting");
        msg->GetArgumentList()->SetString(0, message);

        CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
        CefRefPtr<CefFrame> frame = context->GetFrame();

        // Results in an asynchronous call to
        // SimpleHandler::OnProcessMessageReceived in the browser process
        frame->SendProcessMessage(PID_BROWSER, msg);

        // Return value to JavaScript
        retval = CefV8Value::CreateString("Message sent to C++!");
        return true;
      }
    }

    return false;
  }

 private:
  IMPLEMENT_REFCOUNTING(MyV8Handler);
  DISALLOW_COPY_AND_ASSIGN(MyV8Handler);
};
```

**Add the OnContextCreated implementation** (after OnContextInitialized, before the end of the file):

```cpp
// Called when the JavaScript context is created in the renderer process
void SimpleApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
                                  CefRefPtr<CefFrame> frame,
                                  CefRefPtr<CefV8Context> context) {
  // Debug assertion - crashes if called on wrong thread
  // V8 APIs must only be called from the renderer thread
  CEF_REQUIRE_RENDERER_THREAD();

  // Register JavaScript function 'sayHello' on the global object (window.sayHello)
  CefRefPtr<CefV8Value> object = context->GetGlobal();
  CefRefPtr<CefV8Handler> handler = new MyV8Handler();

  CefRefPtr<CefV8Value> func =
      CefV8Value::CreateFunction("sayHello", handler);
  object->SetValue("sayHello", func, V8_PROPERTY_ATTRIBUTE_NONE);
}
```

**Note:** The SimpleWindowDelegate, SimpleBrowserViewDelegate, and OnContextInitialized implementations remain unchanged from previous steps.

### Platform Entry Points

**Important:** For JavaScript-to-C++ communication to work, the renderer process needs access to `SimpleApp::OnContextCreated` to register the JavaScript function.

- **macOS:** Uses separate helper executables for sub-processes (renderer, GPU, etc.) - update `process_helper_mac.cc`
- **Windows and Linux:** Reuse the main executable for sub-processes - update `cefsimple_win.cc` and `cefsimple_linux.cc`

#### tests/cefsimple/cefsimple_linux.cc

**Update the main function to create SimpleApp before CefExecuteProcess:**

Find:
```cpp
  // CEF applications have multiple sub-processes (render, GPU, etc) that share
  // the same executable. This function checks the command-line and, if this is
  // a sub-process, executes the appropriate logic.
  int exit_code = CefExecuteProcess(main_args, nullptr, nullptr);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }
```

Replace with:
```cpp
  // SimpleApp implements application-level callbacks. It will create the first
  // browser instance in OnContextInitialized() after CEF has initialized.
  CefRefPtr<SimpleApp> app(new SimpleApp);

  // CEF applications have multiple sub-processes (render, GPU, etc) that share
  // the same executable. This function checks the command-line and, if this is
  // a sub-process, executes the appropriate logic.
  int exit_code = CefExecuteProcess(main_args, app, nullptr);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }
```

**Then find the later SimpleApp creation:**

```cpp
  // SimpleApp implements application-level callbacks for the browser process.
  // It will create the first browser instance in OnContextInitialized() after
  // CEF has initialized.
  CefRefPtr<SimpleApp> app(new SimpleApp);
```

**Delete these lines** (since we now create app earlier).

#### tests/cefsimple/cefsimple_win.cc

**Update the RunMain function to create SimpleApp before CefExecuteProcess:**

Find:
```cpp
  // CEF applications have multiple sub-processes (render, GPU, etc) that share
  // the same executable. This function checks the command-line and, if this is
  // a sub-process, executes the appropriate logic.
  exit_code = CefExecuteProcess(main_args, nullptr, sandbox_info);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }
```

Replace with:
```cpp
  // SimpleApp implements application-level callbacks. It will create the first
  // browser instance in OnContextInitialized() after CEF has initialized.
  CefRefPtr<SimpleApp> app(new SimpleApp);

  // CEF applications have multiple sub-processes (render, GPU, etc) that share
  // the same executable. This function checks the command-line and, if this is
  // a sub-process, executes the appropriate logic.
  exit_code = CefExecuteProcess(main_args, app, sandbox_info);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }
```

**Then find the later SimpleApp creation:**

```cpp
  // SimpleApp implements application-level callbacks for the browser process.
  // It will create the first browser instance in OnContextInitialized() after
  // CEF has initialized.
  CefRefPtr<SimpleApp> app(new SimpleApp);
```

**Delete these lines** (since we now create app earlier).

#### tests/cefsimple/process_helper_mac.cc

**Add include at the top:**

```cpp
#include "tests/cefsimple/simple_app.h"
```

**Update the main function to create SimpleApp before CefExecuteProcess:**

Find:
```cpp
return CefExecuteProcess(main_args, nullptr, nullptr);
```

Replace with:
```cpp
// SimpleApp implements application-level callbacks for the sub-process.
// This allows SimpleApp::OnContextCreated to be called in the renderer process.
CefRefPtr<SimpleApp> app(new SimpleApp);

// Execute the sub-process.
return CefExecuteProcess(main_args, app, nullptr);
```

**Note:** Unlike the main executable, the macOS helper doesn't have a separate browser process initialization section, so there's no duplicate SimpleApp creation to remove.

#### tests/cefsimple/CMakeLists.txt (macOS only)

**Update the helper sources to include simple_app:**

Find:
```cmake
# cefsimple helper sources.
set(CEFSIMPLE_HELPER_SRCS_MAC
  process_helper_mac.cc
  )
```

Replace with:
```cmake
# cefsimple helper sources.
set(CEFSIMPLE_HELPER_SRCS_MAC
  process_helper_mac.cc
  simple_app.cc
  simple_app.h
  simple_handler.cc
  simple_handler.h
  )
```

This ensures the helper process can compile and link the SimpleApp code.

**Note:** We're including simple_handler.cc/h in the helper sources even though SimpleHandler is never used in renderer processes (only SimpleApp::OnContextCreated is called). For a production application, you could create a separate CefApp-derived class for the renderer process (e.g., `SimpleRendererApp`) to avoid linking browser-process-only dependencies like SimpleHandler into the helper executables.

**Reconfigure CMake (macOS only)** to pick up the CMakeLists.txt changes:

```bash
cmake -B build -G Xcode
```

### tests/cefsimple/simple_handler.h

**Add process message handler:**

```
/* Detailed source-code truncated for AI context efficiency. */
```

### tests/cefsimple/simple_handler.cc

**Add at the top** (after the existing includes):

```cpp
#include <sstream>
```

**Update OnLoadEnd** to inject a test button (replace the background color change with button injection):

```cpp
// Frame load finished in the browser process
void SimpleHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
                               CefRefPtr<CefFrame> frame,
                               int httpStatusCode) {
  CEF_REQUIRE_UI_THREAD();

  if (!frame->IsMain()) {
    return;
  }

  // Inject a test button to call our C++ function
  std::stringstream ss;
  ss << "var button = document.createElement('button');"
     << "button.textContent = 'Call C++ Function';"
     << "button.style.position = 'fixed';"
     << "button.style.top = '10px';"
     << "button.style.left = '10px';"
     << "button.style.zIndex = '10000';"
     << "button.style.backgroundColor = '#4CAF50';"
     << "button.style.color = 'white';"
     << "button.style.padding = '10px 15px';"
     << "button.style.border = 'none';"
     << "button.style.borderRadius = '4px';"
     << "button.style.cursor = 'pointer';"
     << "button.onclick = function() {"
     << "  var result = sayHello('Hello from JavaScript!');"
     << "  alert(result);"
     << "};"
     << "document.body.appendChild(button);";

  frame->ExecuteJavaScript(ss.str(), frame->GetURL(), 0);
}
```

**Add OnProcessMessageReceived** (after OnLoadEnd, before OnBeforeClose):

```cpp
// Process message received in the browser process
bool SimpleHandler::OnProcessMessageReceived(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefProcessId source_process,
    CefRefPtr<CefProcessMessage> message) {
  CEF_REQUIRE_UI_THREAD();

  // Handle message from MyHandler::Execute() in the renderer process
  if (message->GetName() == "greeting") {
    CefString msg = message->GetArgumentList()->GetString(0);

    // Show the message in a JavaScript alert
    std::stringstream ss;
    ss << "alert('C++ received: " << msg.ToString() << "');";
    frame->ExecuteJavaScript(ss.str(), frame->GetURL(), 0);

    return true;
  }

  return false;
}
```

**Note:** OnTitleChange and OnBeforeClose remain unchanged from previous steps.

## Build and Run

```bash
# Rebuild using the same commands as Step 0

# Windows
cmake --build build --config Release --target cefsimple

# Linux
cmake --build build --target cefsimple

# macOS
cmake --build build --config Release --target cefsimple
```

**Run:** See Step 0 for platform-specific run instructions.

Now you'll see a button in the top-left corner of every page. Click it to:

1. Call JavaScript `sayHello()` function
2. JavaScript sends message to C++ via process message
3. C++ receives message in browser process
4. C++ sends alert back to JavaScript

## What's Happening

**New concepts:**

1. **Multi-process architecture:**
    - Browser process (UI, main logic)
    - Renderer process (usually one per origin, runs web content)
    - Processes communicate via messages

2. **Renderer process (SimpleApp):**
    - `OnContextCreated()` - Called when JavaScript context is created
    - `CefV8Value::CreateFunction()` - Register a JavaScript function
    - `CefV8Handler::Execute()` - Handle JavaScript function calls

3. **Process messages:**
    - `CefProcessMessage::Create()` - Create a message
    - `CefFrame::SendProcessMessage()` - Send from renderer to browser
    - `CefClient::OnProcessMessageReceived()` - Receive in browser process

**Flow:**

1. Renderer process creates → `OnContextCreated()` registers `sayHello()` function
2. User clicks button → JavaScript calls `sayHello('Hello from JavaScript!')`
3. `MyV8Handler::Execute()` receives call, creates process message
4. Message sent to browser process
5. `SimpleHandler::OnProcessMessageReceived()` handles message in browser process
6. C++ executes JavaScript to show alert

**Important notes:**

- JavaScript function runs in renderer process (sandboxed)
- C++ handler runs in browser process (has full access)
- Messages are the bridge between processes
- Messages can contain simple data types (strings, ints, lists, dictionaries), binary data, and shared memory regions

**Learn more:**

- **[JavaScriptIntegration.md](javascript_integration.md)** - Complete guide to V8 JavaScript integration:
    - Window binding and extensions
    - V8 value creation and type conversion
    - Working with V8 contexts
    - JavaScript objects and arrays
    - Function handlers (CefV8Handler)

- **[GeneralUsage.md](general_usage.md#inter-process-communication-ipc)** - Inter-Process Communication section:
    - Process startup messages
    - Process runtime messages (CefProcessMessage)
    - Asynchronous JavaScript bindings
    - Generic message router for request/response patterns
    - Custom IPC implementations

# Step 7: Multiple Browser Support

**Goal:** Track multiple browser instances and only quit the application when all browsers are closed.

## What We're Adding

In Steps 1-6, the application only supported a single browser. When that browser closed, the app quit immediately. Now we'll add:

- Browser instance tracking (map using browser ID as key)
- Proper lifecycle management (add on create, remove on close)
- Only quit when the last browser closes
- Working `CloseAllBrowsers()` implementation
- A second button to create popup windows

## Why This Matters

The single-browser approach from earlier steps has limitations:

- **Quits too early**: If user creates a popup, closing the main window quits immediately (popup also closes)
- **No browser tracking**: Can't iterate over browsers to close them all
- **CloseAllBrowsers() is a stub**: Doesn't actually do anything

Multi-browser tracking is essential for real applications that support popups, new windows, or multiple browser instances.

## Modified Files

### tests/cefsimple/simple_handler.h

**Add browser tracking and lifecycle methods:**

```
/* Detailed source-code truncated for AI context efficiency. */
```

**Changes:**

- Added `#include <map>` for browser tracking container
- Added `OnAfterCreated()` to track browser creation
- Added `browser_map_` member to store all browser instances (keyed by browser ID)
- Added `is_closing_` flag to prevent new browsers during shutdown
- Changed `IsClosing()` to return the actual flag instead of hardcoded `false`

### tests/cefsimple/simple_handler.cc

**Add includes for callbacks and closure tasks** (after the existing includes):

```cpp
#include "include/base/cef_callback.h"
#include "include/wrapper/cef_closure_task.h"
```

**Add OnAfterCreated** (new method, add after OnTitleChange):

```cpp
void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // Add browser to our tracking map
  browser_map_[browser->GetIdentifier()] = browser;
}
```

**Update OnLoadEnd** to add second button (replace the existing OnLoadEnd):

```
/* Detailed source-code truncated for AI context efficiency. */
```

**Update OnBeforeClose** (replace the existing OnBeforeClose):

```cpp
void SimpleHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // Remove browser from our tracking map
  browser_map_.erase(browser->GetIdentifier());

  // Only quit when all browsers are closed
  if (browser_map_.empty()) {
    CefQuitMessageLoop();
  }
}
```

**Update CloseAllBrowsers** (replace the existing stub implementation):

```cpp
void SimpleHandler::CloseAllBrowsers(bool force_close) {
  // CloseAllBrowsers can be called from anywhere (e.g., macOS menu's Quit command),
  // but CEF browser operations must run on the UI thread. Check if we're already
  // on the UI thread; if not, post a task to run this method on the UI thread.
  if (!CefCurrentlyOn(TID_UI)) {
    CefPostTask(TID_UI, base::BindOnce(&SimpleHandler::CloseAllBrowsers, this,
                                        force_close));
    return;
  }

  is_closing_ = true;

  if (browser_map_.empty()) {
    return;
  }

  // Iterate over browsers and request close
  // Use a copy because browser_map_ will be modified during iteration (OnBeforeClose)
  BrowserMap browser_map_copy = browser_map_;
  for (auto& pair : browser_map_copy) {
    pair.second->GetHost()->CloseBrowser(force_close);
  }
}
```

**Note:** Constructor, OnTitleChange, OnProcessMessageReceived, and ShowMainWindow remain unchanged from previous steps.

**Changes:**

- Added `OnAfterCreated()`: Adds browser to `browser_map_` when created (keyed by browser ID)
- Updated `OnLoadEnd()`: Added second button "Create Popup Window" (blue, positioned below first button)
- Updated `OnBeforeClose()`: Removes browser from map by ID, only quits when map is empty
- Implemented `CloseAllBrowsers()`: Sets `is_closing_` flag, iterates over browser_map_ copy, closes each browser
- Uses `CefPostTask()` to ensure execution on UI thread

## Build and Run

```bash
# Rebuild using the same commands as Step 0

# Windows
cmake --build build --config Release --target cefsimple

# Linux
cmake --build build --target cefsimple

# macOS
cmake --build build --config Release --target cefsimple
```

**Run:** See Step 0 for platform-specific run instructions.

## What's Happening

**New concepts:**

1. **Browser lifecycle tracking with map:**
    - Use `std::map<int, CefRefPtr<CefBrowser>>` keyed by browser ID
    - Browser ID obtained via `browser->GetIdentifier()` - unique integer for each browser
    - `OnAfterCreated()` - Called when browser is created, add to map
    - `OnBeforeClose()` - Called when browser is closing, remove from map by ID
    - Only quit when map is empty
    - Why map instead of set? `CefRefPtr` comparison doesn't work as expected for `erase()`, so we key by integer ID

2. **Thread-safe closing:**
    - `CloseAllBrowsers()` uses `CefPostTask()` to execute on UI thread
    - CEF requires most operations on the UI thread
    - `base::BindOnce()` creates a callback that captures `this` and arguments
    - Requires two includes:
        - `include/base/cef_callback.h` - provides `base::BindOnce`
        - `include/wrapper/cef_closure_task.h` - converts callbacks to `CefTask` objects for `CefPostTask`

3. **Container iteration safety:**
    - Create a copy of `browser_map_` before iterating
    - `OnBeforeClose()` modifies the map during iteration (would cause crashes)
    - Copy ensures safe iteration even as browsers close
    - Iterate over `pair.second` to get browser from map entry

**Testing:**

1. Launch the app - main window appears
2. Click "Create Popup Window" - popup opens
3. Close main window - app stays running (popup still open)
4. Close popup - now app quits (all browsers closed)
5. Try creating multiple popups and closing them in different orders

**macOS note:** The Quit menu now works! `CloseAllBrowsers()` is properly implemented, so the macOS application menu's Quit option (which calls `CloseAllBrowsers()`) will close all browsers and quit the app.

**Learn more:**

- **[GeneralUsage.md](general_usage.md#posting-tasks)** - Posting Tasks section:
    - Complete guide to CefPostTask family of functions
    - base::BindOnce and base::Callback usage
    - Thread-safe task posting patterns
    - CefTaskRunner for accessing specific thread message loops
    - Bound methods vs bound functions

# Step 8: Views Styling of Popup Browsers

**Goal:** Customize the appearance and behavior of popup browser windows using the Views framework.

## What We're Adding

In Step 7, clicking "Create Popup Window" opened a new browser, but it used default styling (same size as main window). Now we'll add custom styling for popup windows:

- `OnPopupBrowserViewCreated()` callback in SimpleBrowserViewDelegate
- Custom window creation for popups (smaller size, different from main window)
- Understanding of when to use `OnBeforePopup` vs `OnPopupBrowserViewCreated`

## Why This Matters

CEF provides two callbacks for popup customization with different purposes:

**OnBeforePopup (CefLifeSpanHandler)** - Low-level popup control:

- Called **before** the popup browser is created
- Runs in the browser process
- Can cancel popup creation (return true to cancel)
- Can change the popup's `CefWindowInfo`, `CefClient` and `CefBrowserSettings`
- Use for: Blocking popups, popup policy enforcement, native window parenting

**OnPopupBrowserViewCreated (CefBrowserViewDelegate)** - Views-specific window creation:

- Called **after** the popup browser view is created
- Only called when using the Views framework
- Gives you control over window creation and styling
- Create custom CefWindow with different size, position, title bar, etc.
- Use for: Custom popup window appearance and behavior in Views-based apps

In this step, we use `OnPopupBrowserViewCreated` to create smaller popup windows (600x400) compared to the main window (800x600).

## Modified Files

### tests/cefsimple/simple_app.cc

**Update SimpleBrowserViewDelegate** to add OnPopupBrowserViewCreated (add after GetBrowserRuntimeStyle, before the private section):

```cpp
// Browser view delegate
class SimpleBrowserViewDelegate : public CefBrowserViewDelegate {
 public:
  SimpleBrowserViewDelegate() = default;

  // NEW: Called when a popup browser view is created
  bool OnPopupBrowserViewCreated(
      CefRefPtr<CefBrowserView> browser_view,
      CefRefPtr<CefBrowserView> popup_browser_view,
      bool is_devtools) override {
    // Create a smaller window for popups (600x400 instead of 800x600)
    // We use a custom SimpleWindowDelegate that returns a different size
    CefWindow::CreateTopLevelWindow(
        new SimpleWindowDelegate(popup_browser_view));

    // Returning true indicates we created the window
    return true;
  }

  cef_runtime_style_t GetBrowserRuntimeStyle() override {
    return CEF_RUNTIME_STYLE_ALLOY;
  }

 private:
  IMPLEMENT_REFCOUNTING(SimpleBrowserViewDelegate);
  DISALLOW_COPY_AND_ASSIGN(SimpleBrowserViewDelegate);
};
```

**Update SimpleWindowDelegate** to support custom popup sizes (replace the GetPreferredSize method):

```cpp
  CefSize GetPreferredSize(CefRefPtr<CefView> view) override {
    // Check if this is a popup by seeing if we have a browser yet
    CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
    if (browser && browser->IsPopup()) {
      // Popup windows are smaller
      return CefSize(600, 400);
    }
    // Main window is larger
    return CefSize(800, 600);
  }
```

**Note:** The SimpleWindowDelegate, MyV8Handler, and OnContextInitialized/OnContextCreated implementations remain unchanged from Step 7.

## Build and Run

```bash
# Rebuild using the same commands as Step 0

# Windows
cmake --build build --config Release --target cefsimple

# Linux
cmake --build build --target cefsimple

# macOS
cmake --build build --config Release --target cefsimple
```

**Run:** See Step 0 for platform-specific run instructions.

## What's Happening

**New concepts:**

1. **OnPopupBrowserViewCreated callback:**
    - Called by CEF after a popup browser view is created
    - Only invoked when using Views framework (not for native windows)
    - Parameters:
        - `browser_view` - The parent browser view that initiated the popup
        - `popup_browser_view` - The newly created popup browser view
        - `is_devtools` - True if this is a DevTools popup
    - Return value:
        - `true` - You created the window (CEF won't create a default window)
        - `false` - CEF will create a default window

2. **Custom popup window creation:**
    - We create a new `CefWindow` for the popup using `CefWindow::CreateTopLevelWindow()`
    - Pass the `popup_browser_view` to `SimpleWindowDelegate` (same pattern as main window)
    - The delegate's `GetPreferredSize()` returns different sizes for popups vs main windows
    - `browser->IsPopup()` identifies popup browsers

3. **Popup detection:**
    - `CefBrowser::IsPopup()` returns true for browsers created via `window.open()` or similar
    - Main browser (created in `OnContextInitialized`) returns false
    - We use this to return different window sizes

4. **Alternative approach - GetDelegateForPopupBrowserView:**
    - Instead of using the same delegate for all browser views, you can override `CefBrowserViewDelegate::GetDelegateForPopupBrowserView()` to return a different delegate for popups
    - This allows you to completely separate popup behavior from main window behavior
    - Example: Create a `PopupBrowserViewDelegate` class with different implementations of `OnPopupBrowserViewCreated()`, etc.
    - The approach in this tutorial (same delegate, detect popups with `IsPopup()`) is simpler and works well for most cases
    - Use `GetDelegateForPopupBrowserView` when you need significantly different delegate behavior for popups

**Testing:**

1. Launch the app - main window is 800x600
2. Click "Create Popup Window" - popup opens at 600x400 (smaller)
3. Click "Create Popup Window" from the popup - another 600x400 popup opens
4. All popups use the custom smaller size
5. Close popups - app continues running until all browsers closed

**When to use each callback:**

| Scenario | Use OnBeforePopup | Use OnPopupBrowserViewCreated |
|----------|------------------|-------------------------------|
| Block all popups | ✅ Return true to cancel | ❌ Too late (browser already created) |
| Custom popup window size (Views) | ❌ Limited control | ✅ Full window control |
| Custom popup window styling (Views) | ❌ Limited control | ✅ Full window control |
| Popup policy enforcement | ✅ Can examine URL, features | ❌ Too late |
| Native window popups (non-Views) | ✅ Can modify CefWindowInfo | ❌ Not called for native windows |

**Important notes:**

- `OnPopupBrowserViewCreated` is **only called for Views-based browsers** (our tutorial uses Views)
- If using native platform windows (non-Views), use `OnBeforePopup` and `CefWindowInfo` instead
- Both callbacks can be used together (OnBeforePopup for policy, OnPopupBrowserViewCreated for styling)
- DevTools windows also trigger these callbacks (check `is_devtools` parameter)

# Next Steps

Congratulations! You've built a CEF application from scratch and learned:

- ✅ CEF initialization and lifecycle
- ✅ Views framework for cross-platform UI
- ✅ Browser and window delegates
- ✅ Command-line argument handling
- ✅ Display and load handlers
- ✅ JavaScript execution from C++
- ✅ JavaScript-to-C++ communication via process messages
- ✅ Multiple browser tracking and lifecycle management
- ✅ Custom popup window styling with OnPopupBrowserViewCreated

## Explore More Features

**[cefclient](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/)** - A comprehensive sample application demonstrating:

- Chrome style browsers (full Chrome UI)
- Platform-specific implementations (WinAPI, GTK, Cocoa)
- Off-screen rendering (OSR)
- Custom scheme handlers (`client://` URLs)
- Request interception and modification
- Cookie management
- Dialog handlers
- Context menus
- Drag and drop
- And much more...

**[cef-project](https://github.com/chromiumembedded/cef-project)** - Focused example applications demonstrating specific features:

- **[message_router](https://github.com/chromiumembedded/cef-project/blob/master/examples/message_router)** - JavaScript bindings using CefMessageRouter for request/response patterns
- **[resource_manager](https://github.com/chromiumembedded/cef-project/blob/master/examples/resource_manager)** - Resource request handling using CefResourceManager
- **[scheme_handler](https://github.com/chromiumembedded/cef-project/blob/master/examples/scheme_handler)** - Custom protocol handlers using CefSchemeHandlerFactory

## Learn Advanced Topics

**[General Usage](general_usage.md)** - Complete CEF documentation covering:

- Multi-process architecture in depth
- Threading model and task posting
- Request handling and network interception
- JavaScript integration patterns
- Custom protocol handlers
- Performance optimization
- Security considerations

## Using the C API

**[Using The CAPI](using_the_capi.md)** - Complete guide to the CEF C API:

- Manual reference counting patterns
- Structure allocation and ownership
- String handling
- Thread safety and atomic operations
- Complete working examples in [cefsimple_capi](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/)

## Using Claude Code for Implementation

Want help implementing additional features in your CEF application? The CEF project includes instructions for using Claude Code to assist with tasks like adding custom URL schemes, JavaScript-to-C++ communication, request interception, and more.

See the [CEF Client Development Guide](https://github.com/chromiumembedded/cef/blob/master/tools/claude/CLIENT_DEVELOPMENT.md) for step-by-step instructions.

---

### Installer (`docs/installer.md`)

# CEF Installer

**Available starting with CEF version 151.1.**

The CEF Installer Library is part of the standard bootstrap binary and provides
automatic CEF version management for Windows applications using the
[bootstrap architecture](sandbox_setup.md). It downloads, installs, updates, and
uninstalls CEF from a shared installation directory so that multiple applications
can share a single managed copy of a CEF version (including libcef and all
associated DLLs and resources).

Installer behavior is optional. It activates only when a `CEF_INSTALLER_CONFIG`
resource is embedded in the client DLL or bootstrap executable. Without that
resource, the client DLL loads the libcef DLL in the usual way with no installer
involvement.

The authoritative reference is
[libcef_dll/bootstrap/installer/README.md](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md).
This document is a brief overview; follow the links below for full details.

## What It Does

- **Automatic resolution**: On startup, the bootstrap finds the best compatible
  CEF version already installed, or downloads and installs one from the CDN.
  Downloaded archives are verified against their hash and signed catalog before
  installation.
- **Shared installation**: Multiple apps share versioned CEF installations
  under a common directory (typically `%LocalAppData%\CEF\` for standard users
  or `%ProgramFiles%\CEF\` for admin installs).
- **Updates**: Apps can check for newer CEF versions in the background through
  the `RunInstaller` API, or manually via `/cef-update` (when enabled, see below).
- **Uninstall and cleanup**: Removing an app's registration automatically
  prunes CEF versions that no other app needs.
- **Version safety**: Revoked versions are excluded, and optional launch-health
  tracking rolls back versions that crash repeatedly.
- **Enterprise support**: Group Policy controls can restrict download sources,
  enforce offline mirrors, or disable external downloads entirely.

## Quick Start

### 1. Add an installer configuration resource

Embed a `CEF_INSTALLER_CONFIG` JSON resource in your client DLL (or bootstrap
`.exe`):

```json
{
  "appid": "A3B9C4D5-E6F7-4A8B-9C0D-E1F2A3B4C5D6",
  "vmin": "151.1",
  "vmax": "",
  "abi_hash": "1234567890ABCDEF",
  "launch_health": "explicit"
}
```

Key fields:

| Field | Purpose |
|-------|---------|
| `appid` | Unique UUID for your application (never changes). |
| `vmin` | Minimum compatible CEF version. |
| `vmax` | Maximum compatible CEF version (empty = no upper bound). |
| `abi_hash` | Sandbox compatibility hash from `cef_version.h`. |
| `launch_health` | `"off"`, `"explicit"` (recommended), or `"exit_code"`. |

For the full field reference, see
[Configuration Fields](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md#2-configuration-fields).

### 2. Build with the standard binary distribution (cefclient example)

The standard Windows binary distribution provides an opt-in CMake flag for
building cefclient with installer support:

```bash
cmake -G "Visual Studio 17" -A x64 -DUSE_INSTALLER=On ..
```

This Release-only configuration:
- Builds the bootstrap and sandbox libraries
- Embeds the `CEF_INSTALLER_CONFIG` resource in the client DLL
- Stages only the bootstrap `.exe`, client DLL, and `chrome_elf.dll`

Replace the sample application identity (`appid`) before production use. See
[Build Integration](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md#build-integration)
for resource embedding details.

### 3. Sign your binaries

The bootstrap verifies that `chrome_elf.dll` and the `.exe` share the same
code-signing certificate. Both must be signed before deployment. CEF
installations are signed and verified separately using their own catalog and
certificate.

See [Code Signing](code_signing.md#windows) for application signing commands and
[signed catalog creation](code_signing.md#create-a-signed-catalog) for CEF
distributions.

## Command-Line Usage

Run the bootstrap executable with installer flags:

```
MyApp.exe /cef-update                    # Check for and install updates
MyApp.exe /cef-update /cef-background    # Silent background update
MyApp.exe /cef-uninstall                 # Unregister and prune unused versions
```

These commands require `enable_explicit_modes: true` in the bootstrap's
embedded configuration. See
[Command-Line Options](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md#command-line-options).

## Background Updates from Code

Client DLLs can trigger updates programmatically via the `RunInstaller` export:

```cpp
auto run_installer = reinterpret_cast<RunInstallerFunc>(
    GetProcAddress(GetModuleHandle(nullptr), "RunInstaller"));
const char* result = run_installer("update", config_json.c_str());
```

The result is a JSON string indicating success or failure. Available commands:
`install`, `update`, `uninstall`, `query`, and `launch_success`.

For the full API, result format, and extended configuration options, see
[Background Update API](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md#background-update-api).

## Version Selection

The installer picks the best CEF version from multiple sources:

1. **Installed versions** in the shared directory (or an app-specific
   `install_path` if configured)
2. An optional **bundled version** shipped with the app (`bundled_cef_path`)
3. **CDN download** when no local version qualifies

Among qualifying candidates, newer wins; ties go to the installed copy. Revoked
versions are excluded from normal selection, and crash-disqualified versions
(when launch-health tracking is enabled) are deprioritized.

For the complete decision tree, see
[Version Selection](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md#version-selection).

### Bundled CEF Modes

Applications can optionally ship CEF alongside their own binaries instead of
relying solely on the shared installation directory and CDN downloads.

- **`bundled_cef_path`**: Points to a full CEF distribution directory (with
  `cef_version.json`, `catalog.cat`, and `Release/libcef.dll`). The bundled
  version participates in normal version selection — it is compared against
  installed versions and the newer one wins. It is used in-place and never
  copied to the shared directory. See
  [Bundled Version Behavior](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md#bundled-version-behavior).

- **`unchecked_cef_path`**: Points directly to a directory containing
  `libcef.dll`. When set, this path is checked first and bypasses all version,
  ABI, signature, and revocation checks — the application is fully responsible
  for the integrity of that DLL. If the DLL is absent, the installer falls
  through to normal resolution. See
  [Unchecked CEF Path](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md#unchecked-cef-path).

## Further Reading

| Topic | Link |
|-------|------|
| Full installer reference | [README.md](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/README.md) |
| Security model | [SECURITY.md](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/SECURITY.md) |
| Enterprise policy | [ADMIN_POLICY.md](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/ADMIN_POLICY.md) |
| Testing | [TESTING.md](https://github.com/chromiumembedded/cef/blob/master/libcef_dll/bootstrap/installer/TESTING.md) |
| Bootstrap/client integration | [sandbox_setup.md](sandbox_setup.md) |

---

### Javascript Integration (`docs/javascript_integration.md`)

This page explains how to use V8 JavaScript integration in client applications.

**Contents**

- [Introduction](#introduction)
- [ExecuteJavaScript](#executejavascript)
- [Window Binding](#window-binding)
- [Extensions](#extensions)
- [Basic JS Types](#basic-js-types)
- [JS Arrays](#js-arrays)
- [JS Objects](#js-objects)
  - [Objects with Accessors](#objects-with-accessors)
- [JS Functions](#js-functions)
  - [Functions and Window Binding](#functions-and-window-binding)
  - [Functions and Extensions](#functions-and-extensions)
- [Working with Contexts](#working-with-contexts)
- [Executing Functions](#executing-functions)
  - [Using JS Callbacks](#using-js-callbacks)
  - [Rethrowing Exceptions](#rethrowing-exceptions)

---

# Introduction

Chromium and CEF use the [V8 JavaScript Engine](http://code.google.com/p/v8/) for their internal JavaScript (JS) implementation. Each frame in a browser has its own JS context that provides scope and security for JS code executing in that frame (see the "Working with Contexts" section for more information). CEF exposes a large number of JS features for integration in client applications.

With CEF3 Blink (WebKit) and JS execution run in a separate renderer process. The main thread in a renderer process is identified as TID\_RENDERER and all V8 execution must take place on this thread. Callbacks related to JS execution are exposed via the CefRenderProcessHandler interface. This interface is retrieved via CefApp::GetRenderProcessHandler() when a new renderer process is initialized.

JS APIs that communicate between the browser and renderer processes should be designed using asynchronous callbacks. See the "Asynchronous JavaScript Bindings" section of the [General Usage](general_usage.md) wiki page for more information.

# ExecuteJavaScript

The simplest way to execute JS from a client application is using the CefFrame::ExecuteJavaScript() function. This function is available in both the browser process and the renderer process and can safely be used from outside of a JS context.

```cpp
CefRefPtr<CefBrowser> browser = ...;
CefRefPtr<CefFrame> frame = browser->GetMainFrame();
frame->ExecuteJavaScript("alert('ExecuteJavaScript works!');",
    frame->GetURL(), 0);
```

The above example will cause `alert('ExecuteJavaScript works!');` to be executed in the browser's main frame.

The ExecuteJavaScript() function can be used to interact with functions and variables in the frame's JS context. In order to return values from JS to the client application consider using Window Binding or Extensions.


# Window Binding

Window binding allows the client application to attach values to a frame's `window` object. Window bindings are implemented using the CefRenderProcessHandler::OnContextCreated() method.

```cpp
void MyRenderProcessHandler::OnContextCreated(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefRefPtr<CefV8Context> context) {
  // Retrieve the context's window object.
  CefRefPtr<CefV8Value> object = context->GetGlobal();

  // Create a new V8 string value. See the "Basic JS Types" section below.
  CefRefPtr<CefV8Value> str = CefV8Value::CreateString("My Value!");

  // Add the string to the window object as "window.myval". See the "JS Objects" section below.
  object->SetValue("myval", str, V8_PROPERTY_ATTRIBUTE_NONE);
}
```

JavaScript in the frame can then interact with the window bindings.

```html
<script language="JavaScript">
alert(window.myval); // Shows an alert box with "My Value!"
</script>
```

Window bindings are reloaded each time a frame is reloaded giving the client application an opportunity to change the bindings if necessary. For example, different frames may be given access to different features in the client application by modifying the values that are bound to the window object for that frame.


# Extensions

**Extension support is deprecated in M154.**

Extensions are like window bindings except they are loaded into the context for every frame and cannot be modified once loaded. The DOM does not exist when an extension is loaded and attempts to access the DOM during extension loading will result in a crash. Extensions are registered using the CefRegisterExtension() function which should be called from the CefRenderProcessHandler::OnWebKitInitialized() method.

```cpp
void MyRenderProcessHandler::OnWebKitInitialized() {
  // Define the extension contents.
  std::string extensionCode =
    "var test;"
    "if (!test)"
    "  test = {};"
    "(function() {"
    "  test.myval = 'My Value!';"
    "})();";

  // Register the extension.
  CefRegisterExtension("v8/test", extensionCode, NULL);
}
```

The string represented by `extensionCode` can be any valid JS code. JS in the frame can then interact with the extension code.

```html
<script language="JavaScript">
alert(test.myval); // Shows an alert box with "My Value!"
</script>
```

# Basic JS Types

CEF supports the creation of basic JS data types including undefined, null, bool, int, double, date and string. These types are created using the CefV8Value::Create\*() static methods. For example, to create a new JS string value use the CreateString() method.

```cpp
CefRefPtr<CefV8Value> str = CefV8Value::CreateString("My Value!");
```

Basic value types can be created at any time and are not initially associated with a particular context (see the "Working with Contexts" section for more information).

To test the value type use the Is\*() methods.

```cpp
CefRefPtr<CefV8Value> val = ...;
if (val.IsString()) {
  // The value is a string.
}
```

To retrieve the value use the Get\*Value() methods.

```
CefString strVal = val.GetStringValue();
```

# JS Arrays

Arrays are created using the CefV8Value::CreateArray() static method which accepts a length argument. Arrays can only be created and used from within a context (see the "Working with Contexts" section for more information).

```cpp
// Create an array that can contain two values.
CefRefPtr<CefV8Value> arr = CefV8Value::CreateArray(2);
```

Values are assigned to an array using the SetValue() method variant that takes an index as the first argument.

```cpp
// Add two values to the array.
arr->SetValue(0, CefV8Value::CreateString("My First String!"));
arr->SetValue(1, CefV8Value::CreateString("My Second String!"));
```

To test if a CefV8Value is an array use the IsArray() method. To get the length of an array use the GetArrayLength() method. To get a value from an array use the GetValue() variant that takes an index as the first argument.

# JS Objects

Objects are created using the CefV8Value::CreateObject() static method that takes an optional CefV8Accessor argument. Objects can only be created and used from within a context (see the "Working with Contexts" section for more information).

```cpp
CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(NULL);
```

Values are assigned to an object using the SetValue() method variant that takes a key string as the first argument.

```cpp
obj->SetValue("myval", CefV8Value::CreateString("My String!"));
```

## Objects with Accessors

Objects can optionally have an associated CefV8Accessor that provides a native implementation for getting and setting values.

```cpp
CefRefPtr<CefV8Accessor> accessor = …;
CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(accessor);
```

An implementation of the CefV8Accessor interface that must be provided by the client application.

```cpp
class MyV8Accessor : public CefV8Accessor {
public:
  MyV8Accessor() {}

  virtual bool Get(const CefString& name,
                   const CefRefPtr<CefV8Value> object,
                   CefRefPtr<CefV8Value>& retval,
                   CefString& exception) OVERRIDE {
    if (name == "myval") {
      // Return the value.
      retval = CefV8Value::CreateString(myval_);
      return true;
    }

    // Value does not exist.
    return false;
  }

  virtual bool Set(const CefString& name,
                   const CefRefPtr<CefV8Value> object,
                   const CefRefPtr<CefV8Value> value,
                   CefString& exception) OVERRIDE {
    if (name == "myval") {
      if (value->IsString()) {
        // Store the value.
        myval_ = value->GetStringValue();
      } else {
        // Throw an exception.
        exception = "Invalid value type";
      }
      return true;
    }

    // Value does not exist.
    return false;
  }

  // Variable used for storing the value.
  CefString myval_;

  // Provide the reference counting implementation for this class.
  IMPLEMENT_REFCOUNTING(MyV8Accessor);
};
```

In order for a value to be passed to the accessor it must be set using the SetValue() method variant that accepts AccessControl and PropertyAttribute arguments.

```
obj->SetValue("myval", V8_ACCESS_CONTROL_DEFAULT, 
    V8_PROPERTY_ATTRIBUTE_NONE);
```

# JS Functions

CEF supports the creation of JS functions with native implementations. Functions are created using the CefV8Value::CreateFunction() static method that accepts name and CefV8Handler arguments. Functions can only be created and used from within a context (see the "Working with Contexts" section for more information).

```cpp
CefRefPtr<CefV8Handler> handler = …;
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
```

An implementation of the CefV8Handler interface that must be provided by the client application.

```cpp
class MyV8Handler : public CefV8Handler {
public:
  MyV8Handler() {}

  virtual bool Execute(const CefString& name,
                       CefRefPtr<CefV8Value> object,
                       const CefV8ValueList& arguments,
                       CefRefPtr<CefV8Value>& retval,
                       CefString& exception) OVERRIDE {
    if (name == "myfunc") {
      // Return my string value.
      retval = CefV8Value::CreateString("My Value!");
      return true;
    }

    // Function does not exist.
    return false;
  }

  // Provide the reference counting implementation for this class.
  IMPLEMENT_REFCOUNTING(MyV8Handler);
};
```

## Functions and Window Binding

Functions can be used to create complex window bindings.

```cpp
void MyRenderProcessHandler::OnContextCreated(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefRefPtr<CefV8Context> context) {
  // Retrieve the context's window object.
  CefRefPtr<CefV8Value> object = context->GetGlobal();

  // Create an instance of my CefV8Handler object.
  CefRefPtr<CefV8Handler> handler = new MyV8Handler();

  // Create the "myfunc" function.
  CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);

  // Add the "myfunc" function to the "window" object.
  object->SetValue("myfunc", func, V8_PROPERTY_ATTRIBUTE_NONE);
}
```

```html
<script language="JavaScript">
alert(window.myfunc()); // Shows an alert box with "My Value!"
</script>
```

## Functions and Extensions

Functions can be used to create complex extensions. Note the use of the "native function" forward declaration which is required when using extensions.

```cpp
void MyRenderProcessHandler::OnWebKitInitialized() {
  // Define the extension contents.
  std::string extensionCode =
    "var test;"
    "if (!test)"
    "  test = {};"
    "(function() {"
    "  test.myfunc = function() {"
    "    native function myfunc();"
    "    return myfunc();"
    "  };"
    "})();";

  // Create an instance of my CefV8Handler object.
  CefRefPtr<CefV8Handler> handler = new MyV8Handler();

  // Register the extension.
  CefRegisterExtension("v8/test", extensionCode, handler);
}
```

```html
<script language="JavaScript">
alert(test.myfunc()); // Shows an alert box with "My Value!"
</script>
```


# Working with Contexts

Each frame in a browser window has its own V8 context. The context defines the scope for all variables, objects and functions defined in that frame. V8 will be inside a context if the current code location has a CefV8Handler, CefV8Accessor or OnContextCreated()/OnContextReleased() callback higher in the call stack.

The OnContextCreated() and OnContextReleased() methods define the complete life span for the V8 context associated with a frame. You should be careful to follow the below rules when using these methods:

1. Do not hold onto or use a V8 context reference past the call to OnContextReleased() for that context.

2. The lifespan of all V8 objects is unspecified (up to the GC). Be careful when maintaining references directly from V8 objects to your own internal implementation objects. In many cases it may be better to use a proxy object that your application associates with the V8 context and which can be "disconnected" (allowing your internal implementation object to be freed) when OnContextReleased() is called for the context.

If V8 is not currently inside a context, or if you need to retrieve and store a reference to a context, you can use one of two available CefV8Context static methods. GetCurrentContext() returns the context for the frame that is currently executing JS. GetEnteredContext() returns the context for the frame where JS execution began. For example, if a function in frame1 calls a function in frame2 then the current context will be frame2 and the entered context will be frame1.

Arrays, objects and functions may only be created, modified and, in the case of functions, executed, if V8 is inside a context. If V8 is not inside a context then the application needs to enter a context by calling Enter() and exit the context by calling Exit(). The Enter() and Exit() methods should only be used:

1. When creating a V8 object, function or array outside of an existing context. For example, when creating a JS object in response to a native menu callback.

2. When creating a V8 object, function or array in a context other than the current context. For example, if a call originating from frame1 needs to modify the context of frame2.

# Executing Functions

Native code can execute JS functions by using the ExecuteFunction() and ExecuteFunctionWithContext() methods. The ExecuteFunction() method should only be used if V8 is already inside a context as described in the "Working with Contexts" section. The ExecuteFunctionWithContext() method allows the application to specify the context that will be entered for execution.

## Using JS Callbacks

When registering a JS function callback with native code the application should store a reference to both the current context and the JS function in the native code. This could be implemented as follows.

1\. Create a "register" function in OnJSBinding().

```cpp
void MyRenderProcessHandler::OnContextCreated(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefRefPtr<CefV8Context> context) {
  // Retrieve the context's window object.
  CefRefPtr<CefV8Value> object = context->GetGlobal();

  CefRefPtr<CefV8Handler> handler = new MyV8Handler(this);
  object->SetValue("register",
                   CefV8Value::CreateFunction("register", handler),
                   V8_PROPERTY_ATTRIBUTE_NONE);
}
```

2\. In the MyV8Handler::Execute() implementation for the "register" function keep a reference to both the context and the function.

```cpp
bool MyV8Handler::Execute(const CefString& name,
                          CefRefPtr<CefV8Value> object,
                          const CefV8ValueList& arguments,
                          CefRefPtr<CefV8Value>& retval,
                          CefString& exception) {
  if (name == "register") {
    if (arguments.size() == 1 && arguments[0]->IsFunction()) {
      callback_func_ = arguments[0];
      callback_context_ = CefV8Context::GetCurrentContext();
      return true;
    }
  }

  return false;
}
```

3\. Register the JS callback via JavaScript.

```html
<script language="JavaScript">
function myFunc() {
  // do something in JS.
}
window.register(myFunc);
</script>
```

4\. Execute the JS callback at some later time.

```cpp
CefV8ValueList args;
CefRefPtr<CefV8Value> retval;
CefRefPtr<CefV8Exception> exception;
if (callback_func_->ExecuteFunctionWithContext(callback_context_, NULL, args, retval, exception, false)) {
  if (exception.get()) {
    // Execution threw an exception.
  } else {
    // Execution succeeded.
  }
}
```

See the [Asynchronous JavaScript Bindings](general_usage.md#asynchronous-javascript-bindings) section of the GeneralUsage wiki page for more information on using callbacks.

## Rethrowing Exceptions

If CefV8Value::SetRethrowExceptions(true) is called before CefV8Value::ExecuteFunction\*() then any exceptions generated by V8 during function execution will be immediately rethrown. If an exception is rethrown any native code needs to immediately return. Exceptions should only be rethrown if there is a JS call higher in the call stack. For example, consider the following call stacks where "JS" is a JS function and "EF" is a native ExecuteFunction call:

Stack 1: JS1 -> EF1 -> JS2 -> EF2

Stack 2: Native Menu -> EF1 -> JS2 -> EF2

With stack 1 rethrow should be true for both EF1 and EF2. With stack 2 rethrow should false for EF1 and true for EF2.

This can be implemented by having two varieties of call sites for EF in the native code:

1. Only called from a V8 handler. This covers EF 1 and EF2 in stack 1 and EF2 in stack 2. Rethrow is always true.

2. Only called natively. This covers EF1 in stack 2. Rethrow is always false.

Be very careful when rethrowing exceptions. Incorrect usage (for example, calling ExecuteFunction() immediately after exception has been rethrown) may cause your application to crash or malfunction in hard to debug ways.

---

--- METRICS ---
- Files Extracted: 29
- Estimated Token Budget: ~127753 tokens
- Canonical Reference: https://codewiki.google/github.com/chromiumembedded/cef
