CORS Policy Error When Downloading PDF Files with JavaScript Fetch

3 replies
Last updated: Dec 27, 2021
Hey everyone, I am going to implement PDF file download using javascript and here's the code snippets. But I am getting CORS policy error. Any idea?
  const download = (url, name, redirectTo) => {
    if (!url) {
      throw new Error("Resource URL not provided! You need to provide one");
    }
    fetch(url)
      .then(response => response.blob())
      .then(blob => {
        setFetching(false);
        const blobURL = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = blobURL;
        a.style = "display: none";

        if (name && name.length) a.download = name;
        document.body.appendChild(a);
        a.click();
				navigate(redirectTo)
      })
      .catch(() => setErrors(["Something went wrong in fetching file data for download."]));
  };
AI Update

The CORS error you're encountering is happening because Sanity's Asset CDN has specific CORS configurations that may not allow direct fetch() requests from your domain. Here are a few solutions:

Quick Fix: Use the URL Directly

The simplest approach is to skip the fetch() call entirely and just use the asset URL directly in the anchor tag. Sanity's Asset CDN is designed to serve files with proper headers for direct downloads:

const download = (url, name, redirectTo) => {
  if (!url) {
    throw new Error("Resource URL not provided! You need to provide one");
  }
  
  const a = document.createElement("a");
  a.href = url;
  a.download = name || "download.pdf";
  a.style = "display: none";
  
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  
  navigate(redirectTo);
};

This works because browsers handle the download directly without making a cross-origin request from your JavaScript.

If You Need to Process the File First

If you absolutely need to fetch the blob first (for example, to process it), you have two options:

1. Configure CORS Origins for Your Domain

Add your domain to your Sanity project's CORS settings:

  • Go to manage.sanity.io
  • Select your project
  • Navigate to Settings > API > CORS Origins
  • Add your domain (e.g., https://yourdomain.com or http://localhost:3000 for development)
  • You typically don't need "Allow credentials" for public assets

Note: As mentioned in the CORS Origins documentation, CORS settings configured in the Management Dashboard apply to the Data API but may not automatically apply to the Asset CDN, which could be why you're still seeing issues.

2. Proxy Through Your Backend

If CORS configuration doesn't resolve the issue, you can proxy the request through your own server:

const download = async (url, name, redirectTo) => {
  if (!url) {
    throw new Error("Resource URL not provided!");
  }
  
  try {
    const response = await fetch('/api/download-proxy', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ url })
    });
    
    const blob = await response.blob();
    setFetching(false);
    
    const blobURL = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = blobURL;
    a.download = name;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(blobURL);
    
    navigate(redirectTo);
  } catch (error) {
    setErrors(["Something went wrong in fetching file data for download."]);
  }
};

The direct URL approach is recommended since Sanity's Asset CDN is specifically designed for efficient asset delivery with proper caching and compression.

Show original thread
3 replies
user A
Great! thank you. I didn't know this great feature on sanity management board. It's working now.
user A
Great! thank you. I didn't know this great feature on sanity management board. It's working now.
Great! I’m glad things are working for you. 🙌

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?