Skip to main content
Api

useScript()

Open the live Custom Script example.

This composable wraps Unhead's useScript(), adding Nuxt triggers, bundling, proxying, and reload(). It also has an experimental Partytown path with a smaller API, described below.

Signature

export function useScript<T extends Record<symbol | string, any> = Record<symbol | string, any>>(
  input: UseScriptInput,
  options?: NuxtUseScriptOptions<T>,
): UseScriptContext<UseFunctionType<NuxtUseScriptOptions<T>, T>>

Arguments

UseScriptInput

Pass a URL string or an object containing script tag attributes.

export type UseScriptInput = string | {
  src: string
  async?: boolean
  defer?: boolean
  type?: string
  integrity?: string
  crossorigin?: string
  innerHTML?: string
  textContent?: string
  referrerpolicy?: string
  // Additional Unhead script and data attributes are supported.
}

Unhead's complete script example shows tag attributes alongside loading options.

NuxtUseScriptOptions

Nuxt Scripts extends Unhead's script triggers and warmup options with these options:

  • resolve - Resolve the loaded SDK with lifecycle-bound signal and waitFor helpers.
  • use - Legacy synchronous or async SDK resolver. Prefer resolve for callback-based readiness.
  • trigger - Triggering Script Loading
  • bundle - Control first-party bundling.
  • proxy - Enable or disable supported collection proxying for a registry script.
  • partytown - Run a supported registry script through Partytown.

partytown: true takes an early SSR path. It writes a <script type="text/partytown" src=""> tag immediately, regardless of trigger, and ignores other script attributes and options such as use, beforeInit, and warmupStrategy. The returned stub reports loaded; load() is a no-op, remove() only disconnects DevTools observation, and proxy, reload(), and lifecycle callbacks are not available. Treat the Partytown return value as an implementation detail.

export type NuxtUseScriptOptions<T = any> = Omit<UseScriptOptions<T>, 'trigger'> & {
  /**
   * The trigger to load the script:
   * - `onNuxtReady` - Load the script when Nuxt is ready.
   * - `manual` - Load the script manually by calling `load()`
   * - `Promise` - Load the script when the promise resolves.
   */
  trigger?: UseScriptOptions<T>['trigger'] | 'onNuxtReady'
  /**
   * Bundle the script as an asset and serve it from your server. This avoids the
   * original host's DNS lookup and keeps the initial request on your origin.
   * - `true` - Bundle the script as an asset.
   * - `'force'` - Bundle and download the script again instead of using the build cache.
   * - `false` - Do not bundle the script. (default for plain useScript calls)
   *
   * @deprecated Bundling is enabled automatically for registry scripts that support it.
   * Set `bundle: false` on a registry script to disable it.
   */
  bundle?: boolean | 'force'
  /**
   * Load the script in a web worker using Partytown.
   * When enabled, adds `type="text/partytown"` to the script tag.
   * Requires @nuxtjs/partytown to be installed and configured separately.
   * @see https://partytown.qwik.dev/
   */
  partytown?: boolean
  /**
   * Control proxying for this script.
   * When `false`, collection requests go directly to the third-party server.
   * When `true`, collection requests are proxied through `/_scripts/p/`.
   * This option applies to registry scripts and defaults to their declared
   * `proxy` capability.
   */
  proxy?: boolean
  /**
   * Skip schema validation for the script input. Use this for development stubs
   * that do not load the actual script.
   */
  skipValidation?: boolean
  /**
   * Specify a strategy for warming up the connection to the third-party script.
   *  - `false` - Disable preloading.
   *  - `'preload'` - Preload the script.
   *  - `'preconnect'` | `'dns-prefetch'` - Preconnect to the script origin.
   */
  warmupStrategy?: false | 'preload' | 'preconnect' | 'dns-prefetch'
}

Return

For the base context API, see Unhead's proxy and direct-access examples. The proxied functions guide explains how calls queue before a script loads.

Outside the Partytown path, the returned object includes:

  • proxy - A typed proxy that queues calls until loading finishes
  • status - Reactive ref with the script status: 'awaitingLoad' | 'loading' | 'loaded' | 'error' | 'removed'
  • load() - Function to manually load the script
  • signal - An AbortSignal scoped to this composable consumer
  • dispose() - Release this consumer's callbacks and triggers without removing the shared script
  • script - The shared Unhead script instance
  • remove() - Remove the shared script for every consumer
  • reload() - Function to remove and reload the script (see below)
  • onLoaded() and onError() - Script lifecycle callbacks

Each call receives its own consumer scope. Vue disposes that scope when its component unmounts, while the shared script remains available to other callers. Call remove() only to remove the script globally.

Lifecycle-aware SDK readiness

Use resolve({ waitFor }) when a vendor exposes a callback that fires after the script element's load event. Listener cleanup and abort rejection are then tied to the shared script lifecycle.

const sdk = useScript<{ ready: true }>('https://example.com/sdk.js', {
  resolve: ({ waitFor }) => waitFor<{ ready: true }>((resolve) => {
    window.onExampleReady = () => resolve({ ready: true })
    return () => delete window.onExampleReady
  }),
})

const api = await sdk.load()

reload()

Removes the script, inserts it again, and re-executes it. Use this for a script that scans the DOM once and must scan again after SPA navigation.

const { reload } = useScript('https://example.com/dom-scanner.js')

// Reload when navigating
watch(() => route.path, () => reload())

Prefer the vendor's SPA API when one exists. For example, iubenda's _iub.cs.api.activateSnippets() activates newly added blocked snippets without reloading the whole script.

Was this page helpful?