#1637·chromedp

Expose Chrome 150 foreground-tab and tab-strip metadata

Author: pirateCreated Jul 19, 2026Updated Jul 20, 2026

Current package version

github.com/chromedp/chromedp v0.16.0

Feature request: expose Chrome 150 foreground-tab and tab-strip metadata

Chrome 150 now exposes authoritative browser-UI tab state through CDP. It would be useful for chromedp to provide a high-level, read-only way to determine:

  • which tab is selected in each Chrome window;
  • each tab's tab-strip index, pinned state, and group ID;
  • the containing Chrome window ID; and
  • the relationship between a browser tab and chromedp page target/context(s).

This is especially valuable when attaching to a user-owned browser or sharing a headed browser with a human. chromedp.Targets(ctx) currently enumerates page-like targets; neither its result order nor creation order identifies the tab selected in Chrome's UI.

Why this was not possible before

Historically CDP exposed renderer/page targets but not the embedder's tab-strip state. The usual workarounds are not equivalent:

  • document.hasFocus(), document.visibilityState, and focus/blur listeners are renderer-level signals.
  • Page.bringToFront and Target.activateTarget change the active tab and can raise the browser window, so they cannot perform a non-disruptive read.
  • Emulation.setFocusEmulationEnabled changes renderer focus behavior rather than reporting real tab selection.
  • --disable-backgrounding-occluded-windows, --disable-renderer-backgrounding, and --disable-background-timer-throttling affect scheduling/rendering, not browser UI state.
  • Page.addScriptToEvaluateOnNewDocument can install heuristics, but scripts cannot observe authoritative tab-strip order, pinning, grouping, or window membership.

This is why previous answers correctly focused on explicit activation: #1101, #1291, and #1365 use Target.activateTarget or Page.bringToFront; #1604 uses Target.createTarget(background: true) to avoid initially selecting a new tab. Those APIs solve mutations, not discovery.

Chrome 150 protocol support

Chrome 150 Stable adds Target.TargetInfo.embedderData for targets of type "tab":

go
infos, err := target.GetTargets().
    WithFilter([]*target.FilterEntry{
        {Type: "tab", Exclude: false},
        {Exclude: true},
    }).Do(ctx)

The JSON object can contain:

json
{
  "tabStripIndex": 0,
  "tabActive": true,
  "tabPinned": false,
  "tabGroupId": "optional-group-id"
}

The current chromedp/cdproto target.Info already includes EmbedderData jsontext.Value, so the raw field is available in the latest generated protocol package. The remaining opportunity is typed parsing and a discoverable chromedp-level API.

Possible shapes could include:

go
type TabInfo struct {
    TargetID  target.ID
    Active    bool
    Index     int
    Pinned    bool
    GroupID   string
    WindowID  browser.WindowID
    Targets   []*target.Info
}

tabs, err := chromedp.Tabs(ctx)
tab, err := chromedp.TabInfo(ctx)

I do not have a strong preference on the exact API. An incremental implementation could first add a typed helper around target.Info.EmbedderData, followed by a chromedp.Tabs inventory grouped/ordered by Chrome window. Chrome <150 and embedders without the data should return an explicit unavailable result rather than infer it from page order.

Implementation details worth preserving:

  • The metadata is on "tab" targets, not "page" targets.
  • One tab may contain multiple page targets under Chromium's multi-page architecture. Target.autoAttachRelated can identify related targets; URL matching or a one-tab/one-page assumption is unsafe.
  • Browser.getWindowForTarget returns the containing Chrome window ID.
  • The metadata is currently pull-based; metadata-only changes do not generate Target.targetInfoChanged events.
  • tabActive means selected within its containing Chrome window. Multiple Chrome windows can each have an active tab even though only one native window/app is foreground at the OS level.

References:

Related chromedp issues

  • #1604 — open a new tab without switching focus (CreateTarget(...).WithBackground(true))
  • #1365 — activate a tab with Page.bringToFront
  • #1291 — activate a tab with Target.activateTarget
  • #1101 — switch/foreground a tab
  • #250 and #228 — early tab-handling and multiple-tab API discussions
  • #1309 — concurrent/background work and renderer behavior
  • #1019 — Page.addScriptToEvaluateOnNewDocument

The proposed feature is complementary to all of these. It should not activate a tab, change chromedp's current context semantics, raise an OS window, or change existing focus emulation/background flags. It simply exposes Chrome's real current tab-strip snapshot so applications no longer need to guess or mutate browser state to discover it.