1. The browser module #
A Chromium driven by k6.
Script #
import { browser } from 'k6/browser';
import { check } from 'k6';
export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: { browser: { type: 'chromium' } },
},
},
thresholds: {
browser_web_vital_lcp: ['p(75)<2500'],
browser_web_vital_cls: ['p(75)<0.1'],
},
};
export default async function () {
const page = await browser.newPage();
try {
await page.goto('https://boutique.example.org/');
await page.locator('input[name="q"]').fill('casque');
await page.locator('button[type="submit"]').click();
await page.waitForSelector('.resultats');
check(await page.locator('h1').textContent(), { 'titre présent': (t) => t.includes('Résultats') });
} finally {
await page.close();
}
}docker run --rm -i grafana/k6:latest-with-browser run - < ui.jsThe module measures Core Web Vitals (browser_web_vital_lcp, cls, inp, fcp, ttfb) like a real user.
Good practice: Combine a few browser VUs (user experience) and many HTTP VUs (load) in the same test: you then measure the degradation users feel when the backend is under pressure.
2. Synthetic monitoring #
Testing continuously, not just before a release.
Principle #
Synthetic monitoring regularly replays (every minute, from several regions) a journey or a request and alerts on failure. It detects an outage even without real traffic (at night, on a rarely visited page).
| Tool | Usage |
|---|---|
| Prometheus Blackbox exporter | Simple HTTP, TCP, ICMP, DNS probes, open source |
| Grafana Synthetic Monitoring | Probes and k6 scripts from global points of presence (Grafana Cloud) |
| Scheduled k6 (cron, Kubernetes CronJob) | Full k6 scripts run periodically, results sent to Prometheus |
Blackbox exporter #
# prometheus.yml
scrape_configs:
- job_name: sondes-http
metrics_path: /probe
params: { module: [http_2xx] }
static_configs:
- targets: [https://boutique.example.org, https://api.example.org/health]
relabel_configs:
- { source_labels: [__address__], target_label: __param_target }
- { source_labels: [__param_target], target_label: instance }
- { target_label: __address__, replacement: blackbox:9115 }- alert: SiteInjoignable
expr: probe_success{job="sondes-http"} == 0
for: 3m
labels: { severity: critical }