Index of every page on this site: llms.txt
Skip to main content
Api

useScript()

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.

To set these options for every script, use defaultScriptOptions in your Nuxt config.

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 (see below)

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.

onLoaded() and onError()

Register a callback for the script's terminal event. onLoaded() receives the script instance. onError() receives an Error when your use or resolve option throws, rejects, or returns no API. When the browser fails to load the file, for example because of an ad blocker or a network error, the argument is undefined.

const { onLoaded, onError, status } = useScript('https://example.com/sdk.js')

onLoaded((sdk) => {
  sdk.init()
})

onError((error) => {
  // `error` is undefined when the file itself failed to load.
  console.warn('SDK failed to load', error ?? status.value)
})
  • Register onError() during setup, before the script can fail. A failed load disposes the consumer, so a later onError() call on the same result never runs. A new useScript() call made after the failure runs its onError() immediately when you register it in the same tick.
  • A later onLoaded() call runs immediately when the script already loaded.
  • Both return a function that unregisters the callback.
  • Pass { key } to register a callback once. A second callback with the same key is ignored.
  • Callbacks never run during SSR. Read status in the template to render a fallback.
<template>
  <p v-if="status === 'error'">
    The map could not load. Check your ad blocker and try again.
  </p>
</template>

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?