PDF viewer showing CORS error on first attempt but works on second try

I’m having a weird problem with displaying PDF files. When users click a button to open a PDF document, the first click always fails with a CORS error message saying ‘Access-Control-Allow-Origin’ header is present on the requested resource. The viewer shows nothing at all. But if I click the same button again, it works perfectly and the PDF loads fine.

The PDF files are coming from an API and stored on Google’s storage servers, so I can’t change anything about the hosting setup.

HTML code:

<a href="{{file.url}}" class="pdf-viewer-btn"><i class="fa fa-view"></i></a>

JavaScript:

$('.pdf-viewer-btn').click(function(e) {
   e.preventDefault();
   var pdfUrl = "https://docs.google.com/viewer?url=" + $(this).attr('href');
   window.open(pdfUrl, "_blank", "scrollbars=yes,resizable=yes");
});

Also noticed that popups don’t work on mobile browsers because of popup blockers.

same issue here with google cloud storage pdfs. the viewer can’t handle redirects from api endpoints on first load. double-encode your pdf url before passing it to the viewer - encodeURIComponent(encodeURIComponent(file.url)). fixed the cors timing issue for me without adding delays or extra requests.

The CORS issue happens because Google Viewer needs time to fetch your PDF from the external server. First request usually times out or gets blocked, but the second works since the file’s cached.

Don’t fight browser limitations and CORS policies - set up a simple automation workflow instead. Create a flow that:

  1. Monitors PDF requests
  2. Pre-processes files through a proxy
  3. Serves them directly without CORS headaches
  4. Handles mobile compatibility automatically

This fixes your mobile popup problem too. You can serve PDFs inline or through a proper modal instead of relying on popups.

I’ve built similar document systems before - automation always beats working around browser quirks. You get consistent behavior everywhere.

Check out Latenode for this setup. It handles file processing workflows really well without messing with server configs: https://latenode.com

The Problem:

You’re encountering a 403.4 HTTPS connection required error when using Google Drive Viewer with PDFs served from your API via Google Cloud Storage. The first click to open a PDF fails, but subsequent clicks succeed. This is due to the viewer’s initial request timing out or being blocked due to CORS restrictions before a successful connection is established. The problem is exacerbated on mobile devices due to popup blockers.

:thinking: Understanding the “Why” (The Root Cause):

The Google Drive Viewer makes a preflight request (OPTIONS request) to check if the server allows cross-origin access before fetching the PDF. If this initial request fails due to timing issues, authentication problems, or CORS misconfigurations on your server, the viewer will not load the PDF. However, subsequent clicks often work because the browser has already established a connection, bypassing the preflight check, or the PDF is cached. The use of window.open() further complicates matters on mobile browsers, where popup blockers often interfere.

:gear: Step-by-Step Guide:

  1. Convert PDFs to Base64 Data URIs: The most effective solution is to eliminate the need for external requests to your Google Cloud Storage PDFs altogether. Use a library like pdf-lib (or a similar library in your preferred language) to convert the PDF into a Base64-encoded data URI on the client-side before attempting to display it. This avoids CORS issues entirely, as you are no longer making a cross-origin request.

    // Example using pdf-lib (replace with your actual API call)
    async function displayPdf(pdfUrl) {
        const pdfBytes = await fetch(pdfUrl).then(res => res.arrayBuffer());
        const pdfDoc = await PDFDocument.load(pdfBytes);
        const base64Pdf = pdfDoc.toBase64();
        displayPdfInViewer(base64Pdf); // custom function to render the PDF
    }
    
    function displayPdfInViewer(base64Pdf) {
        // Replace with your method of displaying the PDF using the base64 string.
        // Example using an iframe:
        const iframe = document.createElement('iframe');
        iframe.src = `data:application/pdf;base64,${base64Pdf}`;
        document.body.appendChild(iframe);
    }
    
    $('.pdf-viewer-btn').click(function(e) {
        e.preventDefault();
        const pdfUrl = $(this).attr('href');
        displayPdf(pdfUrl);
    });
    
  2. Handle Mobile Compatibility: To bypass mobile popup blockers, embed the PDF directly into your page using an <iframe> or a similar approach, rather than using window.open(). This provides a much more reliable experience across various mobile browsers. Adapt your displayPdfInViewer function to use an iframe as shown in the example above. This approach provides a consistent user experience across different devices and browsers without relying on potentially unreliable popup windows.

:mag: Common Pitfalls & What to Check Next:

  • pdf-lib Integration: Ensure you have correctly integrated pdf-lib into your project and that you are handling asynchronous operations (using async/await or promises) appropriately. Refer to the pdf-lib documentation for detailed instructions.
  • Base64 Data URI Size: Very large PDFs converted to Base64 data URIs can significantly increase the page load time. Consider alternative strategies like streaming the PDF data if file sizes are extremely large.
  • Error Handling: Implement robust error handling within your displayPdf function to catch potential issues during the PDF conversion or rendering process.

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

It’s a Google Viewer preflight request issue. The first click fails because CORS gets rejected or times out, but then your browser has an established connection for the next attempts. I had the same problem with Azure Blob Storage URLs. Here’s what worked: validate your URL before calling the viewer. Send a fetch request with ‘no-cors’ mode to your PDF endpoint first, then only launch Google Viewer after you get a successful response. This sets up the connection without triggering CORS validation. For mobile, ditch window.open completely and use location.href assignment instead. It gets around popup blockers and works consistently across different mobile browsers.

The double click happens because your browser and Google Viewer keep bouncing authentication headers back and forth. Don’t waste time with CORS timing hacks or delays - just build a proper document pipeline.

Grab PDFs from your API, run them through middleware, and serve with the right headers. This cuts out Google Viewer entirely.

Here’s what works:

  • Pull PDFs from your API
  • Cache temporarily with proper CORS headers
  • Serve via clean URLs any viewer can read
  • Send inline responses on mobile (no popups)

I’ve fixed this before. Preprocess your docs so browsers never hit external API endpoints directly. Kills CORS errors and mobile popup blocks.

Latenode makes these document workflows dead simple. You can build the whole thing in minutes: https://latenode.com

Google Docs Viewer chokes on initial requests to external URLs, especially from API endpoints. The second try works because it’s partially cached or the connection’s already there.

Make a quick HEAD request to your PDF URL first - just to check it’s reachable. Then call Google Viewer. This usually fixes the timing problem.

Better yet, ditch Google Viewer for PDF.js. It handles CORS way better and you get more control over loading. Plus you embed it right in your page instead of opening new windows, which kills that mobile popup blocker issue.

For mobile specifically - use a modal overlay with an iframe for the PDF viewer instead of window.open(). Mobile browsers handle this much better than popups.

This happens because Google Viewer tries to grab your PDF before your storage server’s ready. The auth headers or preflight requests fail on the first try. I’ve faced this with AWS S3 files. A quick fix is to add a short delay before opening the viewer; wrapping your window.open in setTimeout with around 200ms can help. Alternatively, consider using Mozilla’s PDF.js which manages cross-origin requests more effectively. Though this requires hosting PDF.js files yourself, it offers better control over the viewer. For mobile, avoid using popups since mobile browsers tend to block them; a lightbox or modal overlay is a more effective solution.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.