Skip to content

CSP Configuration ​

What is CSP ​

Content Security Policy (CSP) is an HTTP security header that controls which resources your web page is allowed to load. It helps prevent cross-site scripting (XSS) and other code injection attacks by specifying approved sources for scripts, styles, frames, connections, and other resources.

Learn more: MDN — Content Security Policy (CSP)

Why TopBridge Needs CSP ​

TopBridge SDK uses two browser features that a restrictive CSP can block:

  1. WebSocket connections — The SDK communicates with TopBridge App via ws://localhost:8765/v2 (default) or wss://topbridge.topsale.co.nz:8764/v2 (WSS mode). If your CSP restricts connect-src, these connections will be silently blocked — the SDK reports NOT_RUNNING even though TopBridge App is installed and running.

  2. Custom protocol iframe — client.launch.trigger() creates a hidden iframe with src="topsale://callback" to auto-launch the desktop app. If your CSP restricts frame-src, the iframe load will be blocked and the launch fails silently.

Required Configuration ​

connect-src — WebSocket (always required) ​

The SDK always needs WebSocket access to TopBridge App. Both endpoints must be allowed:

Content-Security-Policy: connect-src 'self' ws://localhost:8765 wss://topbridge.topsale.co.nz:8764

Why both endpoints?

Even if you only use the default WS mode (wssEnabled: false), allow both ws://localhost:8765 and wss://topbridge.topsale.co.nz:8764 so that switching wssEnabled at runtime does not break the connection.

frame-src — Launch protocol (conditional) ​

Required only if you use client.launch.trigger() or client.launch.ensureRunning():

Content-Security-Policy: frame-src 'self' topsale:

If you already have a CSP with frame-src, append topsale: to the existing policy:

Content-Security-Policy: frame-src 'self' https://trusted.cdn.com topsale:

Only needed for launch features

If you don't use client.launch.trigger() or client.launch.ensureRunning(), the frame-src topsale: directive is not needed. The connect-src directives above are always required.

Combined policy ​

Most applications should set both directives in a single CSP header:

Content-Security-Policy: connect-src 'self' ws://localhost:8765 wss://topbridge.topsale.co.nz:8764; frame-src 'self' topsale:

Framework-Specific Configuration ​

Next.js (App Router) ​

typescript
// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Content-Security-Policy',
            value: [
              "connect-src 'self' ws://localhost:8765 wss://topbridge.topsale.co.nz:8764",
              "frame-src 'self' topsale:",
            ].join('; '),
          },
        ],
      },
    ]
  },
}

React (Vite / CRA) ​

For Vite, configure CSP via a middleware or hosting config. For CRA, use a <meta> tag in public/index.html:

html
<meta http-equiv="Content-Security-Policy" content="connect-src 'self' ws://localhost:8765 wss://topbridge.topsale.co.nz:8764; frame-src 'self' topsale:">

Vue / Nuxt.js ​

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/**': {
      headers: {
        'Content-Security-Policy': [
          "connect-src 'self' ws://localhost:8765 wss://topbridge.topsale.co.nz:8764",
          "frame-src 'self' topsale:",
        ].join('; '),
      },
    },
  },
})

SvelteKit ​

typescript
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit'

export const handle: Handle = async ({ event, resolve }) => {
  const response = await resolve(event)
  response.headers.set(
    'Content-Security-Policy',
    [
      "connect-src 'self' ws://localhost:8765 wss://topbridge.topsale.co.nz:8764",
      "frame-src 'self' topsale:",
    ].join('; '),
  )
  return response
}

Verification ​

To verify your CSP is correctly configured:

  1. Open your page in a browser
  2. Open DevTools → Console
  3. For WebSocket: call client.printers.list() (or any SDK method that connects). If no CSP violation appears and the method succeeds, connect-src is correctly configured. Look for errors like Refused to connect to 'ws://localhost:8765/...' or Refused to connect to 'wss://topbridge.topsale.co.nz:8764/...'.
  4. For Launch: call client.launch.trigger(). If no CSP violation appears and TopBridge App opens, frame-src is correctly configured. Look for errors like Refused to frame 'topsale://...'.

Common Issues ​

WebSocket connection silently fails ​

Symptom: SDK methods return NOT_RUNNING or TopBridgeConnectionError, but TopBridge App is installed and running.

Cause: CSP is blocking the WebSocket connection to ws://localhost:8765 or wss://topbridge.topsale.co.nz:8764. Check the Console for Refused to connect to 'ws://...' CSP violation messages.

Fix: Add both WebSocket endpoints to your connect-src directive.

Launch silently fails ​

Symptom: ensureRunning() keeps retrying but TopBridge App doesn't open.

Cause: CSP is blocking the topsale: protocol. Check the Console for CSP violation messages.

Mixed with existing CSP ​

If your application already has a CSP header, don't replace it — append the TopBridge directives to your existing policy. If your CSP doesn't have connect-src or frame-src, add the entire directive.

Using <meta> tag vs HTTP header ​

Both approaches work. HTTP headers (set by your server or framework config) take priority over <meta> tags. If both are present, only the HTTP header is used.