Grafana Cloud
Last reviewed: November 5, 2026

Run browser checks on a browser pool

Caution

The browser pool is an experimental feature. Configuration flags and behavior might change in future releases.

By default, the agent starts a Chromium process for each browser check, on the same host and with the same resources as every other check it runs. With a browser pool, the agent instead borrows a browser session from a separate fleet of browser instances. Each instance runs crocochrome, a Chromium supervisor: for each session, it starts a Chromium browser, and it stops the browser and removes its data when the session ends. Each instance runs one session at a time.

Before you begin

The browser pool requires:

  • crocochrome version v0.13.0 or later, or v0.14.0 or later for the unprivileged image.
  • k6 checks enabled on the agent. They’re enabled by default, so don’t set -disable-k6.
  • The agent’s built-in k6 runner. You can’t use the browser pool with a remote k6 runner set with -k6-uri.

When to use a browser pool

Consider a browser pool when a probe runs many browser checks:

  • Resource isolation: Each browser session gets the dedicated CPU and memory of its instance, instead of competing inside the agent with protocol and scripted checks. If Chromium runs out of memory, it affects only that instance, not the agent.
  • Independent scaling: You size and scale the browser fleet separately from the agents.
  • Smaller agents: The agents no longer run Chromium, so they don’t need the -browser image.

If a probe runs only a few browser checks, use the -browser image instead. It’s simpler to operate and needs fewer privileges than the hardened browser pool image. Refer to Browser pool security considerations.

How the browser pool works

For each browser check run, the agent uses a free instance and releases it when the run ends. Several agents, for example the agents in a cluster, can share the same fleet.

If no instance becomes free within a short wait, the check run fails. The agent doesn’t fall back to a local Chromium.

Size the browser pool and the agents

  • Browser pool instances: Run at least as many instances as the peak number of browser checks running at the same time. Browser checks with long frequencies, such as hourly checks, tend to run in bursts. Size the fleet for those bursts.
  • Agents: With Chromium running on the browser pool, a few agents can run many checks of every type, so keep the number of agents small. If you need the probe to keep running when an agent fails, run a cluster of at least two agents.

To size each instance, use the browser check figures in Calculate resource requirements. Each instance runs one session at a time.

Browser pool security considerations

crocochrome is available as two container images:

  • Hardened (default): The supervisor runs Chromium as a separate user, so a compromised browser can’t interfere with the supervisor. To do this, the container needs privilege escalation and a few added Linux capabilities. It meets the Pod Security baseline profile, but not restricted.
  • Unprivileged: Images tagged <version>-unprivileged. The container needs no added capabilities or privilege escalation, and can run with an arbitrary user ID. It meets the restricted profile. Chromium runs as the same user as the supervisor, so a compromised browser can interfere with the supervisor and with later browser sessions on the same instance.

Use the hardened image unless your platform doesn’t allow it, for example because it enforces the restricted profile, a policy engine such as Kyverno or OPA Gatekeeper blocks added capabilities, or it runs on OpenShift. Only use the unprivileged image when you trust both the check scripts and the content of the pages they load, including third-party scripts.

For the security context that each image requires and the trade-offs in detail, refer to Choosing an image in the crocochrome repository.

Warning

The browser pool instances don’t authenticate requests. Anyone who can reach an instance can start browser sessions in your network. Only allow traffic to the instances from the agents, for example with a Kubernetes NetworkPolicy.

Configure the browser pool on Kubernetes

These steps extend Deployment with Kubernetes and work for both the single agent and the cluster examples. They use the browser pool files from the Kubernetes example in the agent GitHub repository.

  1. Get the browser pool deployment files.

    Bash
    wget https://raw.githubusercontent.com/grafana/synthetic-monitoring-agent/main/examples/kubernetes/crocochrome-service.yaml
    wget https://raw.githubusercontent.com/grafana/synthetic-monitoring-agent/main/examples/kubernetes/crocochrome-deployment.yaml

    In these files:

    • The crocochrome Service is headless, so its name resolves to the IP address of every instance. The agent must reach each instance individually. Don’t use a regular ClusterIP Service.
    • terminationGracePeriodSeconds: 320 gives an instance time to finish its active session before it stops. A session can last up to 5 minutes.
    • The securityContext allows privilege escalation and adds the capabilities that the hardened image needs to run Chromium as a separate user. Don’t change these settings unless you switch to the unprivileged image. Refer to Browser pool security considerations.
    • Chromium writes temporary files to an in-memory volume mounted at /chromium-tmp, which counts toward the memory limit.
  2. Deploy the browser pool.

    Bash
    kubectl apply -f crocochrome-service.yaml
    kubectl apply -f crocochrome-deployment.yaml
  3. In deployment.yaml or cluster-deployment.yaml, uncomment the browser pool arguments:

    YAML
    - --browser-pool-enabled
    - --browser-pool-addresses=crocochrome.synthetic-monitoring.svc.cluster.local:8080

    Then apply the agent manifest again, for example:

    Bash
    kubectl apply -f deployment.yaml
  4. Verify that the agent uses the pool. The agent logs a warning that the browser pool is experimental when it starts, and the sm_agent_browser_pool_instances metric reports the instances it found. Refer to Monitor the browser pool.

To change the size of the fleet, scale the crocochrome Deployment. The agents pick up the change within 15 seconds.

Configure the browser pool with Helm

If you deploy the agent with the Helm chart, the chart can deploy the browser pool and point the agents to it. Enable the browser pool in your values file:

YAML
browserPool:
  enabled: true
  crocochrome:
    # Each instance runs one browser session at a time.
    replicas: 3
    # Set to true to use the unprivileged image.
    unprivileged: false

Then upgrade the release:

Bash
helm upgrade sm-agent oci://ghcr.io/grafana/helm-charts/synthetic-monitoring-agent \
  -n synthetic-monitoring -f values.yaml

The chart sets the image and the security context that the selected image requires. Refer to Browser pool security considerations before you set browserPool.crocochrome.unprivileged. With the browser pool, the agents can use the standard image.

Optionally, the chart can also deploy a NetworkPolicy that only allows the agents to reach the instances. If you enable it and want to scrape the instances’ metrics, which use the same port, add your Prometheus Pods to browserPool.crocochrome.networkPolicy.extraIngressFrom. Refer to the chart README.

Configure the browser pool in other environments

You can run the browser pool anywhere the agents can reach it over HTTP, for example as crocochrome containers with Docker. Set -browser-pool-addresses to the address of each instance, or to a DNS name that resolves to all of them.

Browser pool flags reference

FlagDefaultDescription
-browser-pool-enabledfalseRuns browser checks on the browser pool instead of a local Chromium. Requires -browser-pool-addresses.
-browser-pool-addresses""Comma-separated list of browser pool instances. Uses the same format as cluster join addresses. The port defaults to 8080. Requires -browser-pool-enabled.

The agent doesn’t start if you set only one of these flags. If you disable k6 checks with -disable-k6, the agent logs a warning and ignores the browser pool.

Monitor the browser pool

When the browser pool is enabled, each agent exposes the following metrics. Like the rest of the browser pool, these metrics might change while the feature is experimental.

MetricTypeDescription
sm_agent_browser_pool_instancesGaugeNumber of instances the agent knows about, by state: free, or busy with a session held by this agent.
sm_agent_browser_pool_acquires_totalCounterNumber of session acquisitions, by result: success, exhausted, or error.
sm_agent_browser_pool_acquire_duration_secondsHistogramTime spent acquiring a session.
sm_agent_browser_pool_probes_totalCounterNumber of attempts on an instance, by result: acquired, busy, draining, or error.
sm_agent_browser_pool_releases_totalCounterNumber of session releases, by result: ok or error.

Each instance also exposes metrics on port 8080 at /metrics, including:

MetricTypeDescription
sm_crocochrome_session_activeGauge1 while the instance runs a browser session, 0 otherwise.
sm_crocochrome_sessions_created_totalCounterNumber of browser sessions the instance started.
sm_crocochrome_sessions_terminated_totalCounterNumber of browser sessions that ended, by reason: deleted when the agent released the session, timeout when the session reached the 5-minute limit, or replaced when another session replaced it.
sm_crocochrome_session_duration_secondsHistogramHow long each browser session lasted.
sm_crocochrome_chromium_executions_totalCounterNumber of Chromium processes that ended, by state: finished when the session ended normally, or failed when Chromium exited with an unexpected error.
sm_crocochrome_chromium_resource_usageHistogramMaximum memory used by each Chromium process, by resource: rss.
sm_crocochrome_chromium_oom_kills_totalCounterNumber of times the kernel stopped a process in the container because it ran out of memory during a session.
sm_crocochrome_infoGaugeBuild information, with the crocochrome version in the version label. Always 1.

Because each instance runs one session at a time, avg(sm_crocochrome_session_active) across instances is the share of the fleet in use, from 0 to 1. Use it to decide when to add or remove instances, or as the input of an autoscaling policy for the crocochrome Deployment, for example with a HorizontalPodAutoscaler on an external metric or with KEDA.

With the Helm chart, set browserPool.crocochrome.replicas: null, so that helm upgrade doesn’t reset the number of instances, and add the autoscaler with extraObjects.

Keep some headroom: when every instance is busy, new browser check runs wait and can fail.

To estimate how many instances you need, multiply the rate of new sessions across the fleet, sum(rate(sm_crocochrome_sessions_created_total[5m])), by the average session duration from sm_crocochrome_session_duration_seconds. The result is the average number of busy instances. Add headroom for bursts on top of it.

In a healthy pool:

  • sm_agent_browser_pool_acquires_total{result="exhausted"} doesn’t increase. If it does, browser checks are failing because no instance was free. Add instances.
  • sm_agent_browser_pool_probes_total doesn’t grow much faster than sm_agent_browser_pool_acquires_total. A high ratio means agents often try busy instances. Add instances or reduce the number of agents.
  • sm_agent_browser_pool_releases_total{result="error"} doesn’t increase. Sessions that aren’t released stay busy until the instance ends them after 5 minutes.
  • sm_crocochrome_sessions_terminated_total{reason="timeout"} doesn’t increase. If it does, sessions aren’t released, and their instances stay busy until the 5-minute limit.
  • sm_crocochrome_sessions_terminated_total{reason="replaced"} doesn’t increase. Agents never replace sessions, so if it increases, something other than the agents is using the instances.
  • sm_crocochrome_chromium_executions_total{state="failed"} and sm_crocochrome_chromium_oom_kills_total don’t increase. Out-of-memory kills mean the memory limit of the instances is too low. Use sm_crocochrome_chromium_resource_usage to see how much memory Chromium uses.