Guides

CORS and Security Attributes

Last updated by Harlan Wilton in chore: lint.

Background

When loading scripts from external domains, browsers enforce Cross-Origin Resource Sharing (CORS) policies. CORS controls how resources on one domain can be requested by scripts running on another domain. For third-party scripts, this affects:

  • Whether the browser sends cookies with requests
  • Access to error details for debugging
  • Subresource Integrity (SRI) validation

Default Behavior

Nuxt Scripts applies privacy-focused defaults to all scripts:

<script
  src="https://example.com/script.js"
  crossorigin="anonymous"
  referrerpolicy="no-referrer"
></script>

These defaults:

  • crossorigin="anonymous" - Prevents the script from sending cookies to third-party servers
  • referrerpolicy="no-referrer" - Prevents sharing the page URL with third-party servers

This improves user privacy but may break scripts that require cookies or referrer information.

Common CORS Errors

Script Fails to Load

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource

This occurs when a server doesn't return proper CORS headers but crossorigin="anonymous" is set. Some third-party scripts don't support CORS.

Script Loads but Functions Fail

The script loads but functionality is broken because it expected cookies or session data.

Error Details Hidden

window.onerror = msg => console.log(msg)
// Shows: "Script error." instead of actual error

Without crossorigin, browsers hide error details from external scripts for security.

Configuring CORS Attributes

Per-Script Configuration

Disable CORS attributes for scripts that don't support them:

useScript({
  src: 'https://example.com/script.js',
  crossorigin: false, // Remove crossorigin attribute
  referrerpolicy: false, // Remove referrerpolicy attribute
})

Or use a different crossorigin value:

useScript({
  src: 'https://example.com/script.js',
  crossorigin: 'use-credentials', // Send cookies with request
})

Global Configuration

Change defaults for all scripts:

nuxt.config.ts
export default defineNuxtConfig({
  scripts: {
    defaultScriptOptions: {
      crossorigin: false,
      referrerpolicy: false,
    }
  }
})

Crossorigin Values

ValueCookies SentError DetailsUse Case
anonymousNoYes (if server supports)Privacy-focused default
use-credentialsYesYesScripts requiring auth
falseYesNoScripts without CORS support

Registry Scripts

Many registry scripts already disable CORS attributes because the third-party doesn't support them:

const config = {
  scriptInput: {
    src: 'https://js.stripe.com/basil/stripe.js',
    crossorigin: false,
    referrerpolicy: false,
  }
}

Scripts with crossorigin: false include:

  • Stripe
  • YouTube Player
  • Google Sign-In
  • Google reCAPTCHA
  • Meta Pixel
  • TikTok Pixel
  • X (Twitter) Pixel
  • Snapchat Pixel
  • Cloudflare Web Analytics
  • Lemon Squeezy
  • Matomo Analytics

If a registry script fails, check if CORS configuration needs adjustment.

Subresource Integrity

When using bundled scripts with SRI, you must include crossorigin="anonymous", which Nuxt adds automatically:

nuxt.config.ts
export default defineNuxtConfig({
  scripts: {
    assets: {
      integrity: true, // Automatically sets crossorigin="anonymous"
    }
  }
})

Troubleshooting

Script Won't Load

  1. Check browser console for CORS errors
  2. Set crossorigin: false to disable CORS mode
  3. Verify the third-party server supports CORS headers

Script Loads but Broken

  1. The script may require cookies - try crossorigin: 'use-credentials'
  2. The script may need the referrer - set referrerpolicy: false
  3. Check if the script expects you to load it without CORS attributes

Debugging External Script Errors

To see full error messages from external scripts:

  1. Ensure the script has crossorigin="anonymous"
  2. Verify the server returns Access-Control-Allow-Origin header
  3. If the server doesn't support CORS, you won't get detailed errors

Bundling as Alternative

If CORS issues persist, consider bundling the script to serve it from your own domain, eliminating CORS entirely.