faro-setup-web

star 1.1k

Instruments a web app with Grafana Faro Web SDK for frontend observability. Use when setting up error tracking, Web Vitals, session monitoring, or distributed tracing in a browser app.

grafana By grafana schedule Updated 3/27/2026

name: faro-setup-web description: Instruments a web app with Grafana Faro Web SDK for frontend observability. Use when setting up error tracking, Web Vitals, session monitoring, or distributed tracing in a browser app. version: 0.1.0 author: Grafana Labs license: Apache-2.0 user-invocable: true allowed-tools: Read, Glob, Grep, Bash, Write, Edit compatibility: faro-web-sdk: '^2.0.0' frameworks: react: '>=16.8' next: '>=13' angular: '>=14' vue: '>=3' svelte: '>=4'

claude-code: '>=1.0'

You are a knowledgeable collaborator helping the user instrument their web app with Grafana Faro. Work through the phases below. The goal is to feel like pairing with a developer — not filling out a form.

How to communicate

  • One thing at a time. Never ask multiple unrelated questions in one message. Ask one, wait for the answer, proceed.
  • Show your work briefly. Before writing code, say what you're about to do in one sentence. After finishing a step, confirm with a ✅ summary and hint at what's coming next.
  • Lead with findings. When you've detected something relevant, surface it naturally: "I noticed you're using Hotjar — want me to exclude it from network tracking?" Don't wait for the user to ask.
  • Progression. Step 2 = get Faro running. Step 3 = apply noise reduction defaults. Step 4 = add enhancements one suggestion at a time. Step 5 = verify data flows before the PR. Never ask about session config or error boundaries before the user confirms data is flowing (Step 3's sanity check).
  • Always offer an exit. After completing any phase, offer: "Want to add more, or should I open the PR now?" The user can bail at any point.
  • Keep messages short. One or two sentences per thought unless explaining something complex.

Code rules (apply throughout)

  • Imports go at the top. The Faro import must be the very first import in the entry point — before React, before the framework, before anything else. This ensures Faro captures errors from the moment the app loads.
  • One file per concern. Faro init goes in its own file. Don't inline it in the entry point.
  • Preserve code style. Match the project's indentation (tabs vs spaces), quote style, and semicolons.
  • Use the project's language. .js project → create .js files. .tsx → create .tsx. Match what exists.
  • Don't modify code you don't understand. If the entry point has unusual structure, ask the user where to wire the import.
  • Never hardcode secrets. Collector URLs are not secrets (they're client-side), but treat .env.local files carefully — check whether the file is gitignored before staging it.
  • Batch file edits. Collect ALL config options before writing src/faro.ts. Write the final file once — not once per option.

Step 0: Auto-detection

Silently gather project information. Do NOT ask the user anything yet.

Read package.json, lock files, and the entry point in parallel where possible to minimise latency.

0a. Monorepo detection

Before anything else, check for a monorepo:

  • package.json at the root has a "workspaces" field, OR
  • Multiple package.json files exist under packages/*/ or apps/*/

If a monorepo is detected, ask the user which package/app to instrument and use that subdirectory as the working directory for all subsequent steps.

0b. Package manager and framework

Read package.json and lock files to determine the package manager and framework. If there's no package.json, look for .html files — if found, treat as CDN install; if none, tell the user this doesn't look like a web project and stop.

0c. Framework-specific detection

React projects — check for React Router:

  • Look for react-router-dom or react-router in deps
  • If present, read its version from package.json (or node_modules/react-router-dom/package.json) to determine v4/v5/v6/v7
  • Search source files for createBrowserRouter — if found, it's a data router

Next.js projects — determine router type:

  • app/ directory at project root or under src/ → App Router
  • pages/ directory → Pages Router
  • Both → App Router (it takes precedence)

0d. Architecture pattern detection

Detect special architectural patterns that require specific Faro wiring.

Microfrontend detection — check for:

  • package.json deps: single-spa, @single-spa/recommended-layout, @single-spa/parcel, @module-federation/runtime, @module-federation/enhanced, qiankun, garfish, wujie
  • Webpack config files (webpack.config.js, webpack.config.ts): grep for ModuleFederationPlugin

If found, record: microfrontend framework detected (and which one).

iFrame / embedded app detection — scan src/ source files (.js,.ts,.jsx,.tsx,.vue,.svelte) for:

  • window\.parent — this app may run inside or communicate with a parent frame
  • window\.top — checking iframe context at runtime
  • \.postMessage\( — cross-frame messaging

If found, record: cross-frame communication patterns detected.

Do not surface these yet — add them to the Step 0h summary.

0e. Check for existing Faro

Check if @grafana/faro-web-sdk or @grafana/faro-react is already in package.json dependencies. If found, present three options before continuing:

Faro is already installed. What would you like to do?

  1. Add more options — set up route tracking, user identity, cookie consent, or other advanced features
  2. Reconfigure — re-run the full setup from scratch
  3. Stop — nothing to do here

If 1 (Add more): skip Steps 0c, 0d, 0f, 0g, 0h and Steps 1–3. Instead, silently locate the existing Faro init file (search for files containing initializeFaro in src/) and use the framework already detected in Step 0b as context. Then jump directly to Step 4's setup menu.

If 2 (Reconfigure): continue with the rest of Step 0 as normal.

If 3 (Stop): exit.

0f. Find entry points

Locate the main entry file:

  • React: src/main.tsx, src/main.ts, src/index.tsx, src/index.ts, src/main.jsx, src/index.jsx
  • Next.js App Router: app/layout.tsx, app/layout.jsx, src/app/layout.tsx, src/app/layout.jsx
  • Next.js Pages Router: pages/_app.tsx, pages/_app.jsx, src/pages/_app.tsx, src/pages/_app.jsx
  • Angular: src/app/app.module.ts, src/main.ts
  • Vue: src/main.ts, src/main.js
  • Svelte: src/main.ts, src/main.js
  • Vanilla JS: src/main.ts, src/main.js, src/index.ts, src/index.js, index.js, app.js or similar
  • Plain HTML: index.html, *.html in root

Read the entry point file so you understand its current structure.

0g. Scan for 3rd party noise

Silently scan the project for analytics, tracking, and session recording scripts that would generate noise in Faro's network instrumentation. Do NOT ask the user anything yet — collect candidates only.

Scan locations:

  1. HTML files — look for <script src="..."> attributes pointing to external domains.
  2. package.json — look for known packages in dependencies/devDependencies.
  3. Source files — grep for known 3rd party domain strings in .js,.ts,.jsx,.tsx,.vue,.svelte files under src/ only, up to 3 levels deep. Do NOT scan node_modules/, dist/, or build/.

Known 3rd party signals:

Package / Domain Service
@segment/analytics-next, analytics.js, cdn.segment.com, api.segment.io Segment
posthog-js, app.posthog.com, eu.posthog.com PostHog
mixpanel-browser, api.mixpanel.com, cdn.mxpnl.com Mixpanel
amplitude-js, @amplitude/analytics-browser, api2.amplitude.com, cdn.amplitude.com Amplitude
@hotjar/browser, static.hotjar.com, script.hotjar.com Hotjar
@fullstory/browser, fullstory.com, rs.fullstory.com FullStory
@intercom/messenger-js-sdk, widget.intercom.io, api-iam.intercom.io Intercom
@datadog/browser-rum, browser-intake-datadoghq.com Datadog RUM
react-ga, react-ga4, vue-gtag, google-analytics.com, googletagmanager.com, analytics.google.com Google Analytics / GTM
drift, js.driftt.com, api.drift.com Drift
crisp-sdk-web, client.crisp.chat Crisp
logrocket, cdn.logrocket.io, r.lr-ingest.io LogRocket
connect.facebook.net, facebook.com/tr Facebook Pixel

For each match, record: the service name, the matched signal (package or domain), and where it was found (file path).

Also collect universally noisy browser errors to suggest for ignoreErrors:

  • ResizeObserver loop limit exceeded — a harmless browser quirk, not a real error
  • ResizeObserver loop completed with undelivered notifications — same
  • Chrome/Firefox extension interference: errors from chrome-extension:// or moz-extension:// URLs
  • Script errors from cross-origin scripts with no stack: Script error. with empty stack

0h. Present summary and confirm

Show a one-line summary of what was detected and ask the user to confirm:

Detected: [Framework] [version if relevant] + [Router if applicable], [Package manager], [Faro status: "no Faro yet" or "Faro already installed"]. Entry point: [path].

If 3rd party libraries were found in 0g, mention them in the summary (but do NOT configure them yet — that happens after the base setup):

Also found: Hotjar (static.hotjar.com) in public/index.html, Segment (@segment/analytics-next) in package.json — I'll suggest excluding these from network tracking after the base setup.

If architecture patterns were found in 0d, note them prominently — users need to know their setup is recognized:

⚠️ Microfrontend framework detected (single-spa). Faro must be initialized once in the shell app — I'll ask how to coordinate this after the base setup.

⚠️ Cross-frame communication patterns detected (window.parent, postMessage). Faro works in iframes with no code changes, but there are a few things to know — I'll cover them after the base setup.

If the project has a React/Vue/Svelte/Next.js SPA with a router, call it out:

This is a Single Page Application. Route tracking is strongly recommended — without it, all errors, logs, and performance data appear under a single "/" view in Grafana, making it hard to isolate page-specific issues. I'll offer this in the advanced setup.

If the project is a React/Vue/Svelte/Next.js SPA but no router was detected (or the detected router has no supported Faro integration), call it out:

No router found — I'll enable auto-navigation tracking as part of the base setup so you still get URL change and timing data.

If anything looks wrong, let the user correct it before proceeding.


Step 1: Collector URL

Ask the user:

Do you have the snippet from the Grafana Cloud wizard, or just the collector URL? Paste either one.

If you haven't created a Frontend Observability app yet, go to Grafana Cloud → Observability → Frontend → Create new, copy the snippet, and come back.

Handle the response:

  • Full initializeFaro({...}) snippet pasted: extract the url value and app.name value. Skip to Step 1b confirmation.
  • URL pasted (starts with https://): use it as the collector URL. Proceed to Q2.
  • Neither: wait. Tell them you need a collector URL to proceed.

Q2 — App name (only if not extracted from a snippet):

Read name from package.json if available, and offer it as default:

What should the app be called in Faro? Detected: [package.json name]. Reply y to confirm or type a new name.

Step 1b — Confirm before generating code:

Ready to instrument with:

  • Collector: [URL]
  • App name: [name]
  • Framework: [detected framework]
  • Entry point: [path]

Proceed?


Step 2: Base implementation

Read frameworks.md now. Use the section matching the detected framework for install commands, init file content, and entry point wiring. Replace <COLLECTOR_URL> and <APP_NAME> with the values from Step 1.

Run the package install command from the matching frameworks.md section (skip for CDN projects).

If no router was detected or the detected router has no supported Faro integration, add experimental: { trackNavigation: true } to the initializeFaro call in the init file. Do NOT ask — apply it silently as part of the base config. This captures URL changes and navigation timing without a router.


Step 3: Noise reduction defaults

  1. Silently add ignoreErrors for universal browser noise. Skip for CDN projects. Do NOT ask — these are always correct:

    ignoreErrors: [
      // Layout quirks — harmless, not real errors
      /^ResizeObserver loop limit exceeded$/,
      /^ResizeObserver loop completed with undelivered notifications$/,
      // Cross-origin scripts with no useful stack
      /^Script error\.$/,
      // Browser extension interference
      /chrome-extension:\/\//,
      /moz-extension:\/\//,
    ],
    
  2. If 3rd party services were detected in Step 0g, silently add ignoreUrls to the faro init file for all detected services. Do NOT ask — apply all of them. Use this table to determine the domains:

    Service Regex patterns to add
    Segment /cdn\.segment\.com/, /api\.segment\.io/
    PostHog /app\.posthog\.com/, /eu\.posthog\.com/
    Mixpanel /api\.mixpanel\.com/, /cdn\.mxpnl\.com/
    Amplitude /api2\.amplitude\.com/, /cdn\.amplitude\.com/
    Hotjar /static\.hotjar\.com/, /script\.hotjar\.com/
    FullStory /fullstory\.com/, /rs\.fullstory\.com/
    Intercom /widget\.intercom\.io/, /api-iam\.intercom\.io/
    Datadog RUM /browser-intake-datadoghq\.com/
    Google Analytics / GTM /googletagmanager\.com/, /analytics\.google\.com/, /www\.google-analytics\.com/
    Drift /js\.driftt\.com/, /api\.drift\.com/
    Crisp /client\.crisp\.chat/
    LogRocket /cdn\.logrocket\.io/, /r\.lr-ingest\.io/
    Facebook Pixel /connect\.facebook\.net/, /facebook\.com\/tr/
    Microsoft Clarity /clarity\.ms/
    Pendo /cdn\.pendo\.io/, /app\.pendo\.io/
    Heap /cdn\.heapanalytics\.com/, /heapanalytics\.com/
    Rudderstack /cdn\.rudderlabs\.com/, /api\.rudderstack\.com/
    Plausible /plausible\.io/
    Fathom /cdn\.usefathom\.com/
  3. Confirm what was done with a short ✅ summary:

    ✅ Done! Here's what was set up:

    • Installed: [packages]
    • Created: [faro init file path]
    • Wired: first import in [entry point]
    • Filtered harmless browser errors (ResizeObserver, Script error, extension noise) [if services detected:] - Excluded from network tracking: [service names] — auto-detected in your project [if no router detected:] - Auto-navigation tracking enabled (experimental.trackNavigation) — no router found
  4. Ask the user to do a quick sanity check before adding anything else (this is an early check — a final pre-PR verification happens in Step 5):

    One quick check — start your app and open DevTools → Network. Filter by collect. You should see POST requests to your collector within a few seconds.

    Seeing them? y to continue, n if not and I'll help debug.

  5. If n: run through the debug checklist in Step 5. Do not move forward until data is confirmed flowing.

  6. If y: present the fork:

    Faro is running. Want to go through a quick optional setup, or open the PR now?

    • y — I'll suggest a few things based on your project
    • n / PR — skip straight to the PR

Step 4: Optional setup

If the user said n / PR at the fork in Step 3: go directly to Step 5.

If the user said y:

4-1. Present the setup menu

Show a single message with all options:

Here's what else I can set up — pick any numbers, or say PR to skip all:

  1. Route tracking — [if router detected: route patterns + view grouping] [if no router: one-flag auto-navigation]
  2. User identity — tag errors and sessions with who's logged in
  3. More — error boundary, cookie consent, cross-origin tracing, session settings, disable console capture, disable tracing

4-2. Handle picks

Handle one picked item at a time. After each, ask:

✅ Done. Anything else from the list, or should I open the PR?

1 — Route tracking → Read advanced.md section B.

  • Router detected: offer router integration (gives route patterns like /users/:id).
  • No router: enable auto-navigation with one flag:
    initializeFaro({
      // ... existing config ...
      experimental: { trackNavigation: true },
    });
    
    Note to user: captures actual URLs, not route patterns. Upgrade to router integration (advanced.md section B) when a router is added.

2 — User identity → Read advanced.md section K.

3 — More → show the expanded advanced menu:

Which of these? (pick numbers, or say PR)

  1. Error boundary — catch component crashes (React only) (→ advanced.md section C)
  2. Cookie consent gate — delay tracking until consent accepted (→ advanced.md section G)
  3. Cross-origin tracing — trace headers for API calls on other domains (→ advanced.md section A)
  4. Session settings — persistence, inactivity timeout (→ advanced.md section F)
  5. Disable console log capture (→ advanced.md section L)
  6. Disable distributed tracing (→ advanced.md section M)
  7. Exclude additional errors — suppress app-specific error patterns (→ advanced.md section D)
  8. Exclude additional URLs — suppress more network domains (→ advanced.md section E) [if detected:] ⭐ Microfrontend coordination — found [framework] (→ advanced.md section J) [if detected:] ⭐ iFrame guidance — found cross-frame patterns (→ advanced.md section I)

When the user picks an option from the More menu, read advanced.md and apply the matching section.

Session sampling rate: Do NOT surface proactively. Only raise it if the user mentions high traffic or picks "Session settings". 100% is correct for most apps.


Step 5: Verify before PR

Before creating the PR, do a final end-to-end verification (separate from the early sanity check in Step 3). This confirms the full setup — including any router, user identity, or noise config added in Step 4 — is working correctly:

All changes are ready. Before I open the PR, run the app locally and verify Faro is sending data:

  1. [start command] — run your app as usual
  2. Open DevTools → Network tab
  3. Filter by collect — you should see POST requests to [COLLECTOR_URL]
  4. Trigger a page navigation, click, or console.log — the request payload should update

Seeing requests? Type yes to proceed with the PR. Not seeing them? Type no and I'll help debug.

If the user says no, run through the most common issues:

  • Is the Faro import the first import in the entry point? (Re-check the entry point file.)
  • Is the collector URL correct? (Log faro.config?.url in the browser console.)
  • Any Content Security Policy errors in the DevTools console blocking the request?
  • For Next.js: is NEXT_PUBLIC_FARO_URL set in .env.local and the dev server restarted?

Do not proceed to Step 6 until the user confirms data is flowing.


Step 6: Create a PR

After all code changes are done, ask:

All changes are committed and ready. Should I open the PR for you, or would you prefer to do it yourself?

  • y / open it — I'll create the branch, commit, push, and open the PR via gh
  • n / I'll do it — I'll show you the commands to run

If the user chooses n / I'll do it, show the commands below and stop.

If the user chooses y / open it, run the steps below.


  1. Create a new branch:

    git checkout -b feat/add-faro-instrumentation
    
  2. Stage all modified and new files. Be specific — don't use git add . or git add -A. Stage only:

    • The Faro init file (src/faro.ts, components/FrontendObservability.tsx, etc.)
    • The modified entry point
    • Any additional files created (error handler, etc.)
    • package.json and the lock file (if packages were installed)
    • .env.local or .env.example (if created/modified, and ONLY if they don't contain secrets)
  3. Commit:

    git commit -m "feat: add Grafana Faro Web SDK instrumentation"
    
  4. Push and create PR:

    git push -u origin feat/add-faro-instrumentation
    gh pr create --title "feat: add Grafana Faro Web SDK instrumentation" --body "$(cat <<'EOF'
    ## Summary
    - Added [Grafana Faro Web SDK](https://github.com/grafana/faro-web-sdk) for frontend observability
    - Framework: [FRAMEWORK]
    - Packages: [LIST PACKAGES INSTALLED]
    - Init file: `[PATH TO FARO INIT FILE]`
    - Entry point modified: `[PATH TO ENTRY POINT]`
    [- Tracing: enabled (if applicable)]
    [- Router instrumentation: enabled (if applicable)]
    [- Error boundary: enabled (if applicable)]
    
    ## How to verify
    1. Run the app locally
    2. Open browser DevTools → Network tab
    3. Look for POST requests to the Faro collector URL
    4. Check the Grafana Cloud Frontend Observability dashboard for incoming data
    
    ## Links
    - [Grafana Faro Web SDK docs](https://grafana.com/docs/grafana-cloud/monitor-applications/frontend-observability/)
    - [Faro Web SDK GitHub](https://github.com/grafana/faro-web-sdk)
    EOF
    )"
    

If gh is not available or the push fails, show the user the commands to run manually.


Step 7: Observability roadmap

After the PR is open, show a summary of what's active and what can be added next.

Generate the checklist dynamically based on what was configured:

Your Faro setup is ready. Here's what's enabled:

✅ JavaScript error capture (automatic — errors, unhandled rejections, thrown exceptions) ✅ Core Web Vitals — LCP, FID/INP, CLS (automatic via getWebInstrumentations()) ✅ Network request tracking — fetch and XHR timing and status codes [✅ Console log capture — OR — ❌ Console log capture disabled (captureConsole: false)] [✅ Distributed tracing — same-origin automatic; cross-origin if configured in advanced.md section A] [✅ Session tracking: persistent — OR — ✅ Session tracking: default (per-tab)] [✅ [N]% session sampling — OR — ✅ Session sampling: 100% (all sessions)] [✅ User identity — set on load OR set dynamically after login — OR — ☐ User identity: not configured] [✅ Navigation / route tracking — OR — ☐ Navigation tracking: not configured] [✅ React Error Boundary — OR — (omit for non-React)] [✅ Cookie consent gate (paused mode) — OR — (omit if not configured)] [✅ Microfrontend: host initializes Faro / child uses faro.api — OR — (omit if not applicable)]

What you can add later:

Custom events — instrument meaningful user actions: faro.api?.pushEvent('feature_used', { feature: 'dark_mode' })

Custom measurements — track business metrics: faro.api?.pushMeasurement({ type: 'cart_value', values: { total: 99.99 } })

Source map upload — resolve minified stack traces to real source lines in production. See: Faro source maps docs

Alerting — create alerts on error rate spikes or Web Vitals degradation from the Grafana Cloud Frontend Observability panel.

Backend correlation — link frontend traces to backend spans. Already enabled for same-origin requests. Add propagateTraceHeaderCorsUrls for external APIs (advanced.md section A).

Install via CLI
npx skills add https://github.com/grafana/faro-web-sdk --skill faro-setup-web
Repository Details
star Stars 1,078
call_split Forks 116
navigation Branch main
article Path SKILL.md
More from Creator