Splunk Observability Kubernetes Frontend RUM + Session Replay
Prerequisites
| Tool or access |
Purpose |
Verify |
| Bash and Python 3 |
Run bundled setup and validation helpers |
bash --version && python3 --version |
| Required product/platform access |
Inspect or configure the selected target |
Complete the documented preflight |
| Credential files for live modes |
Keep secrets out of chat |
Verify paths only |
Workflow Overview
┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐
│ Preflight │ → │ Render/review │ → │ Apply/handoff │ → │ Validate evidence │
└───────────┘ └───────────────┘ └───────────────┘ └─────────────────┘
When to Activate
- Wiring a React, Vue, Angular, Next.js, Nuxt, Remix, nginx/httpd, SPA, or MPA frontend to Splunk Browser RUM,
enabling Session Replay, configuring Frustration Signals, preparing browser-side Digital Experience Analytics
(DXA), uploading.
- Preview and review the splunk observability k8s frontend rum setup workflow before any live apply phase.
- Diagnose failed prerequisites, generated assets, configuration, or validation evidence.
Scope
Follow the documented read-only or render-first path whenever it is available.
This skill does not imply permission to mutate live systems. Require explicit
apply flags, protected credentials, and operator review for state changes.
Examples
Inspect the supported setup modes before selecting one:
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh --help
Expected output: usage, supported modes, and required arguments are displayed
without changing the target environment.
Inspect validation modes before running completion checks:
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/validate.sh --help
Expected output: offline, live, and completion options are displayed when the
skill supports them; help exits without mutation.
Troubleshooting
| Issue |
Cause |
Resolution |
| Preflight fails |
A required tool or access path is missing |
Resolve it before rendering or applying |
| Rendered assets are incomplete |
Required non-secret inputs are absent |
Complete intake and render again |
| Apply is blocked |
Review, credentials, or explicit acceptance is missing |
Use the documented handoff |
| Validation is incomplete |
Live evidence is unavailable |
Record the gap and keep completion open |
This skill configures Splunk Browser RUM (@splunk/otel-web 2.x) plus optional Session Replay (Splunk recorder) for frontend applications served from Kubernetes pods. It is a standalone reusable skill: Splunk Browser RUM beacons land directly at rum-ingest.<realm>.observability.splunkcloud.com/v1/rum, so the Splunk OTel Collector is not a prerequisite for the browser side. Use it as the browser instrumentation handoff when a Digital Experience Analytics (DXA) request needs RUM agent setup, source maps, user tracking, session replay, or frustration signals.
Disambiguation: this is Splunk Browser RUM, not AppDynamics BRUM. AppDynamics Browser Real User Monitoring is handled by splunk-appdynamics-eum-setup. The two products and their SDKs are distinct.
Architecture: four injection modes
flowchart TD
spec["template.example<br/>or --guided prompts"] --> render[render_assets.py]
render --> preflight{preflight}
preflight -->|HTTPS check<br/>version pin<br/>distroless detect<br/>ingress-nginx CVE check| mode{injection mode}
mode -->|A.i nginx pod-side| nginxCm["nginx-rum-configmap.yaml<br/>+ deployment-patch.yaml<br/>sub_filter on closing head"]
mode -->|A.ii ingress-nginx| ingressCm["ingress-snippet-patch.yaml<br/>configuration-snippet annotation<br/>requires allow-snippet-annotations:true"]
mode -->|C initContainer| initCm["initcontainer-patch.yaml<br/>busybox sed rewriter<br/>+ shared emptyDir<br/>distroless-safe"]
mode -->|B runtime-config| runtimeCm["runtime-config-configmap.yaml<br/>window.SPLUNK_RUM_CONFIG<br/>+ deployment-patch.yaml<br/>for npm-bundled apps"]
nginxCm --> backup[injection-backup-configmap.yaml]
ingressCm --> backup
initCm --> backup
runtimeCm --> backup
backup --> apply[apply-injection.sh]
apply --> verify["verify-injection.sh<br/>+ --check-server-timing for RUM-to-APM"]
Istio EnvoyFilter / Lua body-rewrite injection is intentionally not rendered. Service-mesh users can use mode A.i (pod-side nginx) like everyone else.
What it renders
k8s-rum/ — only manifests for the chosen injection mode(s):
- Mode A.i:
nginx-rum-configmap.yaml (server-block snippet with sub_filter '</head>' '<the-rendered-snippet></head>';, sub_filter_types text/html;, sub_filter_once on;, optional proxy_set_header Accept-Encoding ""; for proxied flavors), nginx-deployment-patch.yaml.
- Mode A.ii:
ingress-snippet-patch.yaml (strategic-merge of the Ingress object's nginx.ingress.kubernetes.io/configuration-snippet annotation).
- Mode C:
initcontainer-patch.yaml (busybox:1.36 initContainer with shared emptyDir mounted at the served HTML path; auto-routes through the utility image when the target image looks distroless).
- Mode B:
runtime-config-configmap.yaml (contains window.SPLUNK_RUM_CONFIG = {...}), runtime-config-deployment-patch.yaml, bootstrap-snippet.html.
injection-backup-configmap.yaml — snapshot of the original deployment manifest fragment for clean revert.
apply-injection.sh, uninstall-injection.sh, verify-injection.sh, status.sh.
discovery/workloads.yaml, discovery/services.yaml — only with --discover-frontend-workloads.
source-maps/sourcemap-upload.sh — wraps splunk-rum sourcemaps inject --path <dist> and splunk-rum sourcemaps upload --path <dist> --app-name <app> --app-version <version>. Reads SPLUNK_O11Y_TOKEN_FILE.
source-maps/github-actions.yaml — sample GitHub Actions job snippet.
source-maps/gitlab-ci.yaml — sample GitLab CI job snippet.
source-maps/splunk.webpack.js — sample Webpack 5 plugin config using @splunk/rum-build-plugins.
runbook.md — ordered operator workflow.
preflight-report.md — every fail / warn / advisory finding.
handoff-dashboards.sh — calls splunk-observability-dashboard-builder with the rendered spec.
handoff-detectors.sh — calls splunk-observability-native-ops with starter RUM detectors.
handoff-cloud-integration.sh — advisory pointer to splunk-observability-cloud-integration-setup for the existing rum SIM modular input.
handoff-auto-instrumentation.sh — emitted ONLY when validate.sh --check-server-timing shows the backend is missing the traceparent header.
metadata.json — spec digest, preflight verdicts, rendered file list, target workload list.
There is no handoff-base-collector.sh because RUM beacons direct to ingest.
Safety Rules
- Never ask for any credential in conversation. Two distinct token files are honored:
SPLUNK_O11Y_RUM_TOKEN_FILE — RUM access token. Embedded literally into the rendered JS snippet (RUM tokens are inherently public once served to browsers, but the file-path pattern still satisfies the repo's secret-handling rules).
SPLUNK_O11Y_TOKEN_FILE — existing Org Access Token. Reused for splunk-rum sourcemaps upload (org scope, not the RUM token).
setup.sh rejects raw token CLI flags: --rum-token, --access-token, --token, --bearer-token, --api-token, --o11y-token, --sf-token, --hec-token, --platform-hec-token, --api-key.
- Mutating operations are gated.
--apply-injection and --uninstall-injection require --accept-frontend-injection (because both force pod restarts). Session Replay rendering requires --accept-session-replay-enterprise (enterprise-tier feature).
- All rendered scripts are idempotent and refuse to run when expected preconditions (rendered manifest set, backup ConfigMap populated,
kubectl available) are not met.
- The renderer NEVER reads source maps, application source, or any operator JavaScript; it only emits configuration files and helpers.
Primary Workflow
(Optional) Discover frontend workload candidates. Read-only, no mutation:
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh \
--discover-frontend-workloads \
--realm us0
Edit splunk-observability-k8s-frontend-rum-rendered/discovery/workloads.yaml to set per-workload injection_mode.
Render the assets:
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh \
--render \
--realm us0 \
--application-name acme-checkout \
--deployment-environment prod \
--version "${APP_VERSION:?set application version}" \
--workload Deployment/prod/checkout-web=nginx-configmap
Or run guided mode. Walks the operator through every SplunkRum.init knob, every Session Replay knob, every Frustration Signals knob, then writes a spec and renders:
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh --guided
Review splunk-observability-k8s-frontend-rum-rendered/:
preflight-report.md — every fail / warn / advisory finding.
runbook.md — ordered operator steps.
k8s-rum/ — the manifests that will be applied.
Apply (gated):
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh \
--apply-injection \
--accept-frontend-injection
Verify:
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/validate.sh \
--live --check-injection https://checkout.example.com
Injection Modes
| Mode |
When to pick |
Pod changes |
Ingress changes |
A.i nginx-configmap |
Frontend served by nginx in the pod (most React/Vue/Angular SPA dist on nginx:alpine). Default. |
Mount ConfigMap into /etc/nginx/conf.d/. Rollout restart. |
None |
A.ii ingress-snippet |
Cluster runs ingress-nginx and operator owns the Ingress object. Requires allow-snippet-annotations: "true" on the controller (default false since CVE-2021-25742). |
None |
Patch annotation on the Ingress |
C init-container |
Distroless or non-nginx static-file server (httpd, busybox-served, custom). Works with any frontend container. |
Add initContainer + shared emptyDir. Rollout restart. |
None |
B runtime-config |
App already bundles @splunk/otel-web via npm and just needs realm + token + applicationName at runtime. |
Mount ConfigMap of window.SPLUNK_RUM_CONFIG. Rollout restart. |
None |
See references/injection-modes.md for the deep dive (gzip pitfall, distroless caveats, nginx vs nginx-unprivileged conf.d paths, ingress-nginx CVE history).
Session Replay
Enterprise-tier feature. Default off. To enable:
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh \
--render \
--enable-session-replay \
--accept-session-replay-enterprise \
--session-replay-sampler-ratio 0.5
Renders the splunk-otel-web-session-recorder.js script tag and a SplunkSessionRecorder.init(...) call with the new Splunk recorder format (recorder: 'splunk'). The renderer surfaces every privacy and feature knob: maskAllInputs, maskAllText, sensitivityRules[], maxExportIntervalMs, sampler.ratio, features.{canvas, video, iframes, packAssets, cacheAssets, backgroundServiceSrc}. See references/session-replay-privacy.md and the rrweb→Splunk recorder migration table.
Frustration Signals 2.0
The skill exposes the full Frustration Signals 2.0 surface. rageClick is on by default; deadClick, errorClick, and thrashedCursor are opt-in. thrashedCursor has 14 tuning knobs (timeWindowMs, throttleMs, minDirectionChanges, etc.). See references/frustration-signals.md.
Manual Instrumentation
Manual instrumentation hooks (custom workflow spans for the DEA Custom Events tab, SplunkRum.setGlobalAttributes(), enduser.id / enduser.role, per-framework error handlers for React / Vue 2/3 / Angular 1/2+ / Ember) are documented in references/manual-instrumentation.md. The skill renders advisory snippets only; integrating them is the operator's responsibility.
Source Maps
When source_maps.enabled: true (default), the skill renders a source-maps/sourcemap-upload.sh helper plus sample CI snippets. The helper wraps the splunk-rum CLI:
splunk-rum sourcemaps inject --path dist
splunk-rum sourcemaps upload --path dist --app-name "$APP_NAME" --app-version "$APP_VERSION"
Source map upload requires the Org Access Token (SPLUNK_O11Y_TOKEN_FILE), not the RUM token. See references/source-maps.md.
RUM-to-APM Linking
Splunk Browser RUM links front-end traces to back-end APM traces via the Server-Timing: traceparent;desc="00-{trace_id}-{span_id}-01" HTTP response header on backend responses. Backends instrumented via splunk-observability-k8s-auto-instrumentation-setup emit the header automatically. CORS callers need Access-Control-Expose-Headers: Server-Timing. The validation surface includes --check-server-timing <backend-url>; if the backend is missing the header, the skill emits handoff-auto-instrumentation.sh pointing at the auto-instrumentation skill. See references/apm-linking.md.
Hand-offs
- Dashboards: splunk-observability-dashboard-builder — RUM web vitals (LCP, CLS, INP, FCP, TTFB), page-view rate, JS error rate, frustration signal counts, sessions per app, route-change funnels.
- Detectors: splunk-observability-native-ops — web vitals SLO breach, JS error spike, rage-click rate, dead-click ratio, page-view drop.
- Splunk Platform companion: splunk-observability-cloud-integration-setup — toggles the existing
rum SIM modular input from the sim-modular-inputs.md catalog (page_view, client_error, page_view_time p75, web vitals LCP/CLS/FID into Splunk Platform).
- RUM-to-APM linking: splunk-observability-k8s-auto-instrumentation-setup — only emitted as
handoff-auto-instrumentation.sh when --check-server-timing validation fails.
Out of scope
- Backend application auto-instrumentation (handoff to splunk-observability-k8s-auto-instrumentation-setup when
validate.sh --check-server-timing shows missing trace context).
- iOS / Android Mobile RUM (separate Splunk RUM mobile agents, not browser).
- WebView instrumentation inside native apps (advisory only; documented in references/framework-notes.md).
- Modifying application source code or build pipelines beyond the Webpack plugin / CLI source-map helper. Mode B (runtime-config ConfigMap) covers the npm-bundled SDK case at the K8s layer.
- CSP header rewriting (advisory only — emits exact
Content-Security-Policy header lines but does not patch ingress headers).
- Istio EnvoyFilter / Lua body-rewrite injection (intentionally not rendered — mesh users use mode A.i).
- AppDynamics Browser RUM (handled by splunk-appdynamics-eum-setup).
- FedRAMP / GovCloud Browser RUM (not currently supported by the Splunk Browser RUM agent — documented in references/realms-and-endpoints.md).
- Pre-emptive cookie-consent banner integration (operator's responsibility; documented as legal note in references/session-replay-privacy.md).
Validation
bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/validate.sh
Static checks cover:
- YAML well-formedness of every rendered manifest.
- Every
<script src=> is HTTPS (no HTTP).
- Agent version is pinned (refuses
latest unless --allow-latest-version).
- When the agent version is an exact
vX.Y.Z pin, the <script> tag includes a populated integrity="sha384-..." attribute (operator-supplied or skipped with a note).
- When Session Replay is enabled with
recorder: splunk, the rrweb-legacy options (maskTextSelector, maskInputOptions, maskTextClass, inlineImages, collectFonts) are NOT present.
- Mode A.i nginx config includes
sub_filter_types text/html; and either proxy_set_header Accept-Encoding ""; (proxied) or a documented gzip note (static-file).
- Mode C initContainer uses a separate utility image when the target image looks distroless.
- Workload patches target only the specified workload kind/namespace/name.
- Rendered scripts do not echo secrets.
With --live:
--check-injection <url> — curl -sL the served URL and grep for SplunkRum.init(.
--check-session-replay <url> — same plus SplunkSessionRecorder.init( when enabled.
--check-csp <url> — curl -I and parse Content-Security-Policy for required entries.
--check-rum-ingest — DNS + TCP probe of rum-ingest.<realm>.observability.splunkcloud.com:443.
--check-server-timing <backend-url> — curl -sI and grep for Server-Timing.*traceparent. Emits handoff-auto-instrumentation.sh if missing.
See reference.md for the full CLI flag reference and the thirteen references/*.md annexes for deep topical documentation.
1---2name: splunk-observability-k8s-frontend-rum-setup3description: Use when wiring a React, Vue, Angular, Next.js, Nuxt, Remix, nginx/httpd, SPA, or MPA frontend to Splunk Browser RUM, enabling Session Replay, configuring Frustration Signals, preparing browser-side Digital Experience Analytics (DXA), uploading source maps, validating trace linking, or uninstalling RUM. Do not use for AppDynamics BRUM. Render, apply, verify, and uninstall Splunk Browser RUM and browser-side Digital Experience Analytics (DXA) prerequisites plus optional Session Replay injection for Kubernetes- served frontends. Supports nginx sub_filter, ingress-nginx snippets, initContainer HTML rewrites, runtime config, backup and revert manifests, SplunkRum.init options, Frustration Signals, source-map upload helpers, RUM-to-APM Server-Timing validation, multi-workload specs, distroless detection, version pinning, SRI hashes, IE11 opt-in, and dashboard, detector, SIM, and backend auto-instrumentation handoffs.4---56# Splunk Observability Kubernetes Frontend RUM + Session Replay78## Prerequisites910| Tool or access | Purpose | Verify |11|---|---|---|12| Bash and Python 3 | Run bundled setup and validation helpers | `bash --version && python3 --version` |13| Required product/platform access | Inspect or configure the selected target | Complete the documented preflight |14| Credential files for live modes | Keep secrets out of chat | Verify paths only |1516## Workflow Overview1718```text19┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐20│ Preflight │ → │ Render/review │ → │ Apply/handoff │ → │ Validate evidence │21└───────────┘ └───────────────┘ └───────────────┘ └─────────────────┘22```2324## When to Activate2526- Wiring a React, Vue, Angular, Next.js, Nuxt, Remix, nginx/httpd, SPA, or MPA frontend to Splunk Browser RUM,27 enabling Session Replay, configuring Frustration Signals, preparing browser-side Digital Experience Analytics28 (DXA), uploading.29- Preview and review the splunk observability k8s frontend rum setup workflow before any live apply phase.30- Diagnose failed prerequisites, generated assets, configuration, or validation evidence.3132## Scope3334Follow the documented read-only or render-first path whenever it is available.35This skill does not imply permission to mutate live systems. Require explicit36apply flags, protected credentials, and operator review for state changes.3738## Examples3940Inspect the supported setup modes before selecting one:4142```bash43bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh --help44```4546Expected output: usage, supported modes, and required arguments are displayed47without changing the target environment.4849Inspect validation modes before running completion checks:5051```bash52bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/validate.sh --help53```5455Expected output: offline, live, and completion options are displayed when the56skill supports them; help exits without mutation.5758## Troubleshooting5960| Issue | Cause | Resolution |61|---|---|---|62| Preflight fails | A required tool or access path is missing | Resolve it before rendering or applying |63| Rendered assets are incomplete | Required non-secret inputs are absent | Complete intake and render again |64| Apply is blocked | Review, credentials, or explicit acceptance is missing | Use the documented handoff |65| Validation is incomplete | Live evidence is unavailable | Record the gap and keep completion open |6667This skill configures **Splunk Browser RUM** (`@splunk/otel-web` 2.x) plus optional **Session Replay** (Splunk recorder) for frontend applications served from Kubernetes pods. It is a **standalone reusable** skill: Splunk Browser RUM beacons land directly at `rum-ingest.<realm>.observability.splunkcloud.com/v1/rum`, so the Splunk OTel Collector is **not** a prerequisite for the browser side. Use it as the browser instrumentation handoff when a Digital Experience Analytics (DXA) request needs RUM agent setup, source maps, user tracking, session replay, or frustration signals.6869> **Disambiguation**: this is **Splunk Browser RUM**, not **AppDynamics BRUM**. AppDynamics Browser Real User Monitoring is handled by [splunk-appdynamics-eum-setup](../splunk-appdynamics-eum-setup/SKILL.md). The two products and their SDKs are distinct.7071## Architecture: four injection modes7273```mermaid74flowchart TD75 spec["template.example<br/>or --guided prompts"] --> render[render_assets.py]76 render --> preflight{preflight}77 preflight -->|HTTPS check<br/>version pin<br/>distroless detect<br/>ingress-nginx CVE check| mode{injection mode}78 mode -->|A.i nginx pod-side| nginxCm["nginx-rum-configmap.yaml<br/>+ deployment-patch.yaml<br/>sub_filter on closing head"]79 mode -->|A.ii ingress-nginx| ingressCm["ingress-snippet-patch.yaml<br/>configuration-snippet annotation<br/>requires allow-snippet-annotations:true"]80 mode -->|C initContainer| initCm["initcontainer-patch.yaml<br/>busybox sed rewriter<br/>+ shared emptyDir<br/>distroless-safe"]81 mode -->|B runtime-config| runtimeCm["runtime-config-configmap.yaml<br/>window.SPLUNK_RUM_CONFIG<br/>+ deployment-patch.yaml<br/>for npm-bundled apps"]82 nginxCm --> backup[injection-backup-configmap.yaml]83 ingressCm --> backup84 initCm --> backup85 runtimeCm --> backup86 backup --> apply[apply-injection.sh]87 apply --> verify["verify-injection.sh<br/>+ --check-server-timing for RUM-to-APM"]88```8990Istio EnvoyFilter / Lua body-rewrite injection is intentionally **not** rendered. Service-mesh users can use mode A.i (pod-side nginx) like everyone else.9192## What it renders9394- `k8s-rum/` — only manifests for the chosen injection mode(s):95 - Mode A.i: `nginx-rum-configmap.yaml` (server-block snippet with `sub_filter '</head>' '<the-rendered-snippet></head>';`, `sub_filter_types text/html;`, `sub_filter_once on;`, optional `proxy_set_header Accept-Encoding "";` for proxied flavors), `nginx-deployment-patch.yaml`.96 - Mode A.ii: `ingress-snippet-patch.yaml` (strategic-merge of the Ingress object's `nginx.ingress.kubernetes.io/configuration-snippet` annotation).97 - Mode C: `initcontainer-patch.yaml` (`busybox:1.36` initContainer with shared `emptyDir` mounted at the served HTML path; auto-routes through the utility image when the target image looks distroless).98 - Mode B: `runtime-config-configmap.yaml` (contains `window.SPLUNK_RUM_CONFIG = {...}`), `runtime-config-deployment-patch.yaml`, `bootstrap-snippet.html`.99 - `injection-backup-configmap.yaml` — snapshot of the original deployment manifest fragment for clean revert.100 - `apply-injection.sh`, `uninstall-injection.sh`, `verify-injection.sh`, `status.sh`.101- `discovery/workloads.yaml`, `discovery/services.yaml` — only with `--discover-frontend-workloads`.102- `source-maps/sourcemap-upload.sh` — wraps `splunk-rum sourcemaps inject --path <dist>` and `splunk-rum sourcemaps upload --path <dist> --app-name <app> --app-version <version>`. Reads `SPLUNK_O11Y_TOKEN_FILE`.103- `source-maps/github-actions.yaml` — sample GitHub Actions job snippet.104- `source-maps/gitlab-ci.yaml` — sample GitLab CI job snippet.105- `source-maps/splunk.webpack.js` — sample Webpack 5 plugin config using `@splunk/rum-build-plugins`.106- `runbook.md` — ordered operator workflow.107- `preflight-report.md` — every fail / warn / advisory finding.108- `handoff-dashboards.sh` — calls [splunk-observability-dashboard-builder](../splunk-observability-dashboard-builder/SKILL.md) with the rendered spec.109- `handoff-detectors.sh` — calls [splunk-observability-native-ops](../splunk-observability-native-ops/SKILL.md) with starter RUM detectors.110- `handoff-cloud-integration.sh` — advisory pointer to [splunk-observability-cloud-integration-setup](../splunk-observability-cloud-integration-setup/SKILL.md) for the existing `rum` SIM modular input.111- `handoff-auto-instrumentation.sh` — emitted ONLY when `validate.sh --check-server-timing` shows the backend is missing the traceparent header.112- `metadata.json` — spec digest, preflight verdicts, rendered file list, target workload list.113114There is no `handoff-base-collector.sh` because RUM beacons direct to ingest.115116## Safety Rules117118- Never ask for any credential in conversation. Two distinct token files are honored:119 - `SPLUNK_O11Y_RUM_TOKEN_FILE` — RUM access token. Embedded literally into the rendered JS snippet (RUM tokens are inherently public once served to browsers, but the file-path pattern still satisfies the repo's secret-handling rules).120 - `SPLUNK_O11Y_TOKEN_FILE` — existing Org Access Token. Reused for `splunk-rum sourcemaps upload` (org scope, not the RUM token).121- `setup.sh` rejects raw token CLI flags: `--rum-token`, `--access-token`, `--token`, `--bearer-token`, `--api-token`, `--o11y-token`, `--sf-token`, `--hec-token`, `--platform-hec-token`, `--api-key`.122- Mutating operations are gated. `--apply-injection` and `--uninstall-injection` require `--accept-frontend-injection` (because both force pod restarts). Session Replay rendering requires `--accept-session-replay-enterprise` (enterprise-tier feature).123- All rendered scripts are idempotent and refuse to run when expected preconditions (rendered manifest set, backup ConfigMap populated, `kubectl` available) are not met.124- The renderer NEVER reads source maps, application source, or any operator JavaScript; it only emits configuration files and helpers.125126## Primary Workflow1271281. (Optional) Discover frontend workload candidates. Read-only, no mutation:129130 ```bash131 bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh \132 --discover-frontend-workloads \133 --realm us0134 ```135136 Edit `splunk-observability-k8s-frontend-rum-rendered/discovery/workloads.yaml` to set per-workload `injection_mode`.1371382. Render the assets:139140 ```bash141 bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh \142 --render \143 --realm us0 \144 --application-name acme-checkout \145 --deployment-environment prod \146 --version "${APP_VERSION:?set application version}" \147 --workload Deployment/prod/checkout-web=nginx-configmap148 ```1491503. Or run guided mode. Walks the operator through every SplunkRum.init knob, every Session Replay knob, every Frustration Signals knob, then writes a spec and renders:151152 ```bash153 bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh --guided154 ```1551564. Review `splunk-observability-k8s-frontend-rum-rendered/`:157 - `preflight-report.md` — every fail / warn / advisory finding.158 - `runbook.md` — ordered operator steps.159 - `k8s-rum/` — the manifests that will be applied.1601615. Apply (gated):162163 ```bash164 bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh \165 --apply-injection \166 --accept-frontend-injection167 ```1681696. Verify:170171 ```bash172 bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/validate.sh \173 --live --check-injection https://checkout.example.com174 ```175176## Injection Modes177178| Mode | When to pick | Pod changes | Ingress changes |179|------|--------------|-------------|-----------------|180| A.i `nginx-configmap` | Frontend served by nginx in the pod (most React/Vue/Angular SPA dist on `nginx:alpine`). Default. | Mount ConfigMap into `/etc/nginx/conf.d/`. Rollout restart. | None |181| A.ii `ingress-snippet` | Cluster runs ingress-nginx and operator owns the Ingress object. **Requires `allow-snippet-annotations: "true"` on the controller** (default false since CVE-2021-25742). | None | Patch annotation on the Ingress |182| C `init-container` | Distroless or non-nginx static-file server (httpd, busybox-served, custom). Works with any frontend container. | Add initContainer + shared `emptyDir`. Rollout restart. | None |183| B `runtime-config` | App already bundles `@splunk/otel-web` via npm and just needs realm + token + applicationName at runtime. | Mount ConfigMap of `window.SPLUNK_RUM_CONFIG`. Rollout restart. | None |184185See [references/injection-modes.md](references/injection-modes.md) for the deep dive (gzip pitfall, distroless caveats, nginx vs nginx-unprivileged conf.d paths, ingress-nginx CVE history).186187## Session Replay188189Enterprise-tier feature. Default off. To enable:190191```bash192bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/setup.sh \193 --render \194 --enable-session-replay \195 --accept-session-replay-enterprise \196 --session-replay-sampler-ratio 0.5197```198199Renders the `splunk-otel-web-session-recorder.js` script tag and a `SplunkSessionRecorder.init(...)` call with the new Splunk recorder format (`recorder: 'splunk'`). The renderer surfaces every privacy and feature knob: `maskAllInputs`, `maskAllText`, `sensitivityRules[]`, `maxExportIntervalMs`, `sampler.ratio`, `features.{canvas, video, iframes, packAssets, cacheAssets, backgroundServiceSrc}`. See [references/session-replay-privacy.md](references/session-replay-privacy.md) and the rrweb→Splunk recorder migration table.200201## Frustration Signals 2.0202203The skill exposes the full Frustration Signals 2.0 surface. `rageClick` is on by default; `deadClick`, `errorClick`, and `thrashedCursor` are opt-in. `thrashedCursor` has 14 tuning knobs (timeWindowMs, throttleMs, minDirectionChanges, etc.). See [references/frustration-signals.md](references/frustration-signals.md).204205## Manual Instrumentation206207Manual instrumentation hooks (custom workflow spans for the DEA Custom Events tab, `SplunkRum.setGlobalAttributes()`, `enduser.id` / `enduser.role`, per-framework error handlers for React / Vue 2/3 / Angular 1/2+ / Ember) are documented in [references/manual-instrumentation.md](references/manual-instrumentation.md). The skill renders advisory snippets only; integrating them is the operator's responsibility.208209## Source Maps210211When `source_maps.enabled: true` (default), the skill renders a `source-maps/sourcemap-upload.sh` helper plus sample CI snippets. The helper wraps the `splunk-rum` CLI:212213```bash214splunk-rum sourcemaps inject --path dist215splunk-rum sourcemaps upload --path dist --app-name "$APP_NAME" --app-version "$APP_VERSION"216```217218Source map upload requires the **Org Access Token** (`SPLUNK_O11Y_TOKEN_FILE`), not the RUM token. See [references/source-maps.md](references/source-maps.md).219220## RUM-to-APM Linking221222Splunk Browser RUM links front-end traces to back-end APM traces via the `Server-Timing: traceparent;desc="00-{trace_id}-{span_id}-01"` HTTP response header on backend responses. Backends instrumented via [splunk-observability-k8s-auto-instrumentation-setup](../splunk-observability-k8s-auto-instrumentation-setup/SKILL.md) emit the header automatically. CORS callers need `Access-Control-Expose-Headers: Server-Timing`. The validation surface includes `--check-server-timing <backend-url>`; if the backend is missing the header, the skill emits `handoff-auto-instrumentation.sh` pointing at the auto-instrumentation skill. See [references/apm-linking.md](references/apm-linking.md).223224## Hand-offs225226- Dashboards: [splunk-observability-dashboard-builder](../splunk-observability-dashboard-builder/SKILL.md) — RUM web vitals (LCP, CLS, INP, FCP, TTFB), page-view rate, JS error rate, frustration signal counts, sessions per app, route-change funnels.227- Detectors: [splunk-observability-native-ops](../splunk-observability-native-ops/SKILL.md) — web vitals SLO breach, JS error spike, rage-click rate, dead-click ratio, page-view drop.228- Splunk Platform companion: [splunk-observability-cloud-integration-setup](../splunk-observability-cloud-integration-setup/SKILL.md) — toggles the existing `rum` SIM modular input from the [sim-modular-inputs.md](../splunk-observability-cloud-integration-setup/references/sim-modular-inputs.md) catalog (page_view, client_error, page_view_time p75, web vitals LCP/CLS/FID into Splunk Platform).229- RUM-to-APM linking: [splunk-observability-k8s-auto-instrumentation-setup](../splunk-observability-k8s-auto-instrumentation-setup/SKILL.md) — only emitted as `handoff-auto-instrumentation.sh` when `--check-server-timing` validation fails.230231## Out of scope232233- Backend application auto-instrumentation (handoff to [splunk-observability-k8s-auto-instrumentation-setup](../splunk-observability-k8s-auto-instrumentation-setup/SKILL.md) when `validate.sh --check-server-timing` shows missing trace context).234- iOS / Android Mobile RUM (separate Splunk RUM mobile agents, not browser).235- WebView instrumentation inside native apps (advisory only; documented in [references/framework-notes.md](references/framework-notes.md)).236- Modifying application source code or build pipelines beyond the Webpack plugin / CLI source-map helper. Mode B (runtime-config ConfigMap) covers the npm-bundled SDK case at the K8s layer.237- CSP header rewriting (advisory only — emits exact `Content-Security-Policy` header lines but does not patch ingress headers).238- Istio EnvoyFilter / Lua body-rewrite injection (intentionally not rendered — mesh users use mode A.i).239- AppDynamics Browser RUM (handled by [splunk-appdynamics-eum-setup](../splunk-appdynamics-eum-setup/SKILL.md)).240- FedRAMP / GovCloud Browser RUM (not currently supported by the Splunk Browser RUM agent — documented in [references/realms-and-endpoints.md](references/realms-and-endpoints.md)).241- Pre-emptive cookie-consent banner integration (operator's responsibility; documented as legal note in [references/session-replay-privacy.md](references/session-replay-privacy.md)).242243## Validation244245```bash246bash skills/splunk-observability-k8s-frontend-rum-setup/scripts/validate.sh247```248249Static checks cover:250251- YAML well-formedness of every rendered manifest.252- Every `<script src=>` is HTTPS (no HTTP).253- Agent version is pinned (refuses `latest` unless `--allow-latest-version`).254- When the agent version is an exact `vX.Y.Z` pin, the `<script>` tag includes a populated `integrity="sha384-..."` attribute (operator-supplied or skipped with a note).255- When Session Replay is enabled with `recorder: splunk`, the rrweb-legacy options (`maskTextSelector`, `maskInputOptions`, `maskTextClass`, `inlineImages`, `collectFonts`) are NOT present.256- Mode A.i nginx config includes `sub_filter_types text/html;` and either `proxy_set_header Accept-Encoding "";` (proxied) or a documented gzip note (static-file).257- Mode C initContainer uses a separate utility image when the target image looks distroless.258- Workload patches target only the specified workload kind/namespace/name.259- Rendered scripts do not echo secrets.260261With `--live`:262263- `--check-injection <url>` — `curl -sL` the served URL and grep for `SplunkRum.init(`.264- `--check-session-replay <url>` — same plus `SplunkSessionRecorder.init(` when enabled.265- `--check-csp <url>` — `curl -I` and parse `Content-Security-Policy` for required entries.266- `--check-rum-ingest` — DNS + TCP probe of `rum-ingest.<realm>.observability.splunkcloud.com:443`.267- `--check-server-timing <backend-url>` — `curl -sI` and grep for `Server-Timing.*traceparent`. Emits `handoff-auto-instrumentation.sh` if missing.268269See [reference.md](reference.md) for the full CLI flag reference and the thirteen `references/*.md` annexes for deep topical documentation.