This explainer describes a proposed modification to the JavaScript Self-Profiling API that enables conditional exposure of ProfilerMarker values based on context isolation status. The change allows selective disclosure of markers based on their security sensitivity, improving developer experience while maintaining security boundaries.
The current JavaScript Self-Profiling API markers feature has some limitations:
layout, style) in non-isolated contextslayout, style) in non-isolated contextsgc, paint, script) to Cross-Origin Isolated contextsLayout and style state information is already exposed through other browser APIs (DOM APIs and CSSOM), making these markers safe for broader availability without introducing new security risks.
| Context Type | Feature Flag | Available Markers |
|---|---|---|
| Cross-Origin Isolated | Enabled | All markers (gc, layout, paint, script, style) |
| Cross-Origin Isolated | Disabled | None |
| Non-Isolated | Enabled | Limited (layout, style only) |
| Non-Isolated | Disabled | None |
layout: Layout state information is already available via DOM APIs such as getBoundingClientRect(), getComputedStyle(), and layout-triggering operationsstyle: Style computation state is accessible through CSSOM APIs and style recalculation is observable via existing timing mechanismsThe following markers remain restricted to Cross-Origin Isolated contexts due to potential security implications:
gc: Garbage collection timing could leak memory patterns and cross-origin resource informationpaint: Paint timing might reveal information about cross-origin opaque resources that wouldn't pass Timing-Allow-Origin checksscript: Script execution state could expose sensitive timing information about cross-origin activitiesThis approach follows the principle of graduated disclosure, where:
The API surface remains unchanged from a developer perspective. The conditional exposure happens transparently:
// Cross-origin isolated context
const profiler = new Profiler({sampleInterval: 10, maxBufferSize: 1000});
const trace = await profiler.stop();
// trace.samples may contain all marker types
// Non-isolated context
const profiler = new Profiler({sampleInterval: 10, maxBufferSize: 1000});
const trace = await profiler.stop();
// trace.samples may contain layout/style markers only
No changes to trace structure. The marker field in samples will be:
// Set required headers for Cross-Origin Isolation:
// Cross-Origin-Embedder-Policy: require-corp
// Cross-Origin-Opener-Policy: same-origin
const profiler = new Profiler({sampleInterval: 5, maxBufferSize: 1000});
// Trigger various browser activities
document.body.style.color = 'red'; // Style recalculation
document.body.offsetHeight; // Layout
new Array(1000000); // Potential GC
const trace = await profiler.stop();
// Sample output may include all marker types:
console.log(trace.samples);
// [
// { timestamp: 1234.5, stackId: 2, marker: "gc" },
// { timestamp: 1235.0, stackId: 3, marker: "layout" },
// { timestamp: 1235.5, stackId: 1, marker: "style" },
// { timestamp: 1236.0, stackId: 4, marker: "paint" }
// ]
// Regular context (no special headers required)
const profiler = new Profiler({sampleInterval: 5, maxBufferSize: 1000});
// Trigger various browser activities
document.body.style.color = 'blue'; // Style recalculation
document.body.offsetHeight; // Layout
new Array(1000000); // Potential GC (won't be exposed)
const trace = await profiler.stop();
// Sample output with filtered markers:
console.log(trace.samples);
// [
// { timestamp: 1234.5, stackId: 2 }, // gc marker filtered out
// { timestamp: 1235.0, stackId: 3, marker: "layout" }, // allowed
// { timestamp: 1235.5, stackId: 1, marker: "style" }, // allowed
// { timestamp: 1236.0, stackId: 4 } // paint marker filtered out
// ]
const profiler = new Profiler({sampleInterval: 5, maxBufferSize: 1000});
const trace = await profiler.stop();
// No markers regardless of context isolation status:
console.log(trace.samples);
// [
// { timestamp: 1234.5, stackId: 2 },
// { timestamp: 1235.0, stackId: 3 },
// { timestamp: 1235.5, stackId: 1 }
// ]