Install Flawsnap in Svelte and SvelteKit

In SvelteKit the widget goes in src/app.html, the template every page is rendered into, so it loads once and follows client-side navigation.

Steps

  1. 1

    Allow your hosts

    In Flawsnap, add your production and staging domains, plus localhost:5173 for vite dev and localhost:4173 for vite preview, under Security → Allowed domains.

  2. 2

    Add the snippet to the template

    SvelteKit: paste it into the <head> of src/app.html, above %sveltekit.head%. Plain Svelte with Vite: paste it into the <head> of index.html.

  3. 3

    Declare the global

    Add the Window declaration to src/app.d.ts (or a .d.ts of its own).

  4. 4

    Identify signed-in users

    In your root +layout.svelte, call window.Flawsnap?.identify() from an effect when layout data has a user.

  5. 5

    Test it

    Run the dev server, send a test report and check it in the project.

SvelteKit: src/app.html

Every server-rendered and prerendered page uses this template, so one tag covers the whole app. Do not add it with <svelte:head> in a page: that ties it to one route and would load it again as people navigate.

SvelteKit's client-side router changes pages with the History API. Flawsnap follows those changes on its own, so reports carry the right URL and Insights (Pro) sees each route as a screen.

src/app.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://backend.flawsnap.com/widget.js" data-key="pk_…" async></script>
    %sveltekit.head%
  </head>
  <body data-sveltekit-preload-data="hover">
    <div style="display: contents">%sveltekit.body%</div>
  </body>
</html>

Plain Svelte with Vite

Without SvelteKit there is no app.html. Put the same tag in the <head> of the index.html at the project root, next to the <script type="module"> that mounts your app.

Identify the user from layout data

If your root +layout.server.ts returns the user, the layout can pass it to Flawsnap. Effects only run in the browser, so window is always there.

src/routes/+layout.svelte (Svelte 5)
<script lang="ts">
  let { data, children } = $props()

  $effect(() => {
    if (data.user) {
      window.Flawsnap?.identify({ name: data.user.name, email: data.user.email })
    }
  })
</script>

{@render children()}

On Svelte 4, use onMount together with a reactive statement ($: if (browser && data.user) …) with browser from $app/environment.

The global declaration

src/flawsnap.d.ts
// flawsnap.d.ts (anywhere your tsconfig includes)
export {}

declare global {
  interface Window {
    Flawsnap?: {
      open(): void
      identify(reporter: { name?: string; email?: string }): void
      setMetadata(details: Record<string, unknown>): void
      screen(name: string): void
      track(name: string): void
      resetUser(): void
    }
  }
}

If you use kit.csp

SvelteKit can generate a Content Security Policy from kit.csp in svelte.config.js. With one in place, the browser blocks the widget until you allow its host for scripts and for its requests:

svelte.config.js
kit: {
  csp: {
    directives: {
      'script-src': ['self', 'https://backend.flawsnap.com'],
      'connect-src': ['self', 'https://backend.flawsnap.com'],
    },
  },
},

Merge these with your existing directives rather than replacing them.

Troubleshooting

  • [flawsnap] widget disabled: on vite preview: the preview server uses a different port from vite dev. Allow both.
  • The button appears on prerendered pages but not on others: check every page is rendered from src/app.html, not a custom template.
  • A Refused to load the script error: the CSP is missing https://backend.flawsnap.com in script-src.
  • Reports are missing your API calls from the first load: the widget must start before your app makes them, which is why it sits in app.html rather than in a component that mounts later.

Questions

Does Flawsnap work with a static SvelteKit build (adapter-static)?
Yes. Prerendered pages still come from app.html, so the tag is in each one. Allow the domain you deploy to.
Do I need a Svelte package?
No. The widget is a hosted script and works the same in any framework.

Try it on your own site

7-day free trial, then $9 a month for Starter or $19 for Pro, per organization, with unlimited team members.

Updated