29

UPDATE 2016-11-16 9:53am EST

It appears many people are still seeing 204 responses even though Google has claimed to have "fixed" the problem. When I myself tested the loading of a document 50 times, 3 of those times Google returned a 204 response.

Please visit this URL and post a comment of your unhappiness so that we can finally get Google to address and fix the issue once and for all: https://productforums.google.com/forum/?utm_medium=email&utm_source=footer#!msg/docs/hmj39HMDP1M/SR2UdRUdAQAJ

UPDATE 2016-11-04 6:01pm EST

It looks like the service is up and working again! Thanks to Google Docs for addressing the issue and answering my tweets. Hope it's working for all of you too.

UPDATE 2016-11-04 3:33pm EST

There was an update published to https://productforums.google.com/forum/#!msg/docs/hmj39HMDP1M/X6a8xJwLBQAJ which seems to indicate support for the service might be returning and/or there was an issue on their end which caused unintended results. Stay tuned. See comment immediately below:

enter image description here

Original Post on Stack Overflow Starts Here

Our web software used and relied on the Google Docs viewer service to embed documents into our website (via iframe) and to give our customers the ability to view docs without having to open separate applications (via visiting the URL). This functionality was provided by Google for quite some time and had worked perfectly!

Example viewer URL:

https://docs.google.com/viewer?url=http://www.pdf995.com/samples/pdf.pdf

We began to notice, however, that files we were trying to load would only load very rarely. We initially thought there was an issue with their servers so began investigating the header responses we were getting. Particularly, we noted that nearly every request made was returning a 204 No Content response. Very occasionally we got a 200 response.

Here's an example of one of the 204 responses we got:

enter image description here

Here's an example of one of the 200 responses we got (very rare):

enter image description here

After that I searched Google for 204 issues associated with the Google viewer service. I ended up on this page https://productforums.google.com/forum/#!msg/docs/hmj39HMDP1M/X6a8xJwLBQAJ which seems to indicate that Google has suddenly and abruptly discontinued the service. Here's a screenshot of that discussion (as of the time of this post).

enter image description here

Given the fact that a Google "expert" replied to the person's similar inquiry; it seems that they've officially and totally abandoned support for the viewer service.

My questions are the following:

  1. Does anyone else know for certain whether Google officially ended its support of the Google viewer service?

  2. Does anyone know of an updated similar Google product/service (perhaps Google Drive?) that allows a person to do the exact same thing as the viewer service referenced above? Ideally, I'd like a simple URL where I can reference an external document that doesn't have to exist on a Google server but can still reside on my server.

  3. What are some other comparable and free services you can suggest to allow me to embed documents such as Word docs, Excel docs, PowerPoint docs, and PDFs into a website that allows the user to view the documents within the browser without having to have those applications actually installed on their system.

As a final note, I just want to say that for all the good Google does it's incredibly infuriating, frustrating, and annoying that they can offer a service that people rely on for a long time and suddenly pull the plug on it. I'm sure there are many others besides just myself that will never bother voicing concerns over that type of decision. Google corrected the issue and is still good in my book :-)

Thanks ahead of time for your answers!

Art Geigel
  • 1,915
  • 3
  • 22
  • 24
  • 3
    It's worth noting that Google never offered this as a service for developers, and it's not a part of an official and supported API. Finding an endpoint that works is not the same as Google offering a service, and building upon unsupported endpoints comes with risk. – Eric Koleda Nov 04 '16 at 13:24
  • 1
    Fair enough. They tacitly knew, however, that thousands of people relied on the service and integrated it into their applications. – Art Geigel Nov 04 '16 at 15:08
  • 1
    Beyond that, Microsoft offers a similar service and actively promotes it: https://products.office.com/en-US/office-online/view-office-documents-online. It's an inferior product to Google's service because it doesn't support PDF rendering. I simply don't see any reason why Google would turn it off. It's only going to drive people to a competitor's service. I'd gladly pay a monthly fee to continue using Google's. – Art Geigel Nov 04 '16 at 15:14
  • 3
    Mar, 2017. Still doesnt fix – l2aelba Mar 27 '17 at 09:55
  • 4
    July, 2019. Returns 204 – Subash Jul 01 '19 at 08:25
  • 1
    May, 2021. Returns 204 – Laurens May 07 '21 at 12:07
  • November 2021. Still Returns 204 occasionally – Jinson Paul Oct 20 '21 at 13:01
  • No consistent way to reproduce it, but returning 204 very often – link64 Oct 28 '21 at 00:05
  • April 2023, returns 204 occasionally – polkduran Apr 04 '23 at 16:44

10 Answers10

19

I run a service that also relies on embedding the Google Doc Viewer and I have also encountered this issue. I could not find any other comparable service (free or otherwise).

I have come up with a 'hack' that can help you get away with using the Google Doc Viewer. It does require JQuery though. What I do is keep refreshing the iframe every 2 seconds until it finally loads correctly. I also cover the iframe with a loading gif to hide the constant refreshing. My code:

<style>
.holds-the-iframe {
    background:url(/img/loading.gif) center center no-repeat;
}
</style>

<div class="holds-the-iframe">
      <iframe id="iframeID" name="iframeID" src="https://docs.google.com/viewerng/viewer?url=www.example.com&embedded=true"></iframe>
</div>

<script>
function reloadIFrame() {
    document.getElementById("ifm").src=document.getElementById("iframeID").src;
}

timerId = setInterval("reloadIFrame();", 2000);

$( document ).ready(function() {
    $('#iframeID').on('load', function() {
        clearInterval(timerId);
        console.log("Finally Loaded");
    });
});
</script>
Cellydy
  • 1,365
  • 3
  • 15
  • 27
  • I thought about doing something similar. That solution, however, would take way longer to load and also isn't guaranteed to work in the future given the fact they've indicated they'll phase it out. I'm just completely stumped as to why they'd shut it off knowing people use it. This doesn't apply to me, but there are tons of Wordpress plugins that use it so I'm sure a lot of websites have been impacted. – Art Geigel Nov 04 '16 at 15:19
  • 5
    I agree, it's very annoying. Another 'solution' would be to use the Microsoft equivalent `https://view.officeapps.live.com/op/embed.aspx?src=[OFFICE_FILE_URL]` (which only works with office documents) to display the DOC and DOCX files and something like PDF.JS to handle PDF's. Or convert all files to PDF and just use PDF.JS. – Cellydy Nov 04 '16 at 15:31
  • 4
    Thanks. I saw the Microsoft equivalent but also noted it's failure to render PDFs. The Google Viewer was so perfect at what it did though. I've tweeted at [at]GoogleDocs and [at]jrochelle asking for an explanation and to encourage them to give us the service back. Maybe if they see enough outrage they'd consider reversing their course. – Art Geigel Nov 04 '16 at 15:34
  • 1
    @ArtGeigel If you don't forget, please let me know if you find anything interesting out! – Cellydy Nov 04 '16 at 15:39
  • Of course @Cellydy! Some people have been retweeting my complaint so perhaps we'll end up on their radar. I'll keep you posted. – Art Geigel Nov 04 '16 at 15:58
  • Check out the most recent post on https://productforums.google.com/forum/#!msg/docs/hmj39HMDP1M/X6a8xJwLBQAJ. It looks like they might be bringing it back! – Art Geigel Nov 04 '16 at 19:30
  • Hey @Cellydy I think we're back up and running now. Test it out on your end. – Art Geigel Nov 04 '16 at 21:47
  • @ArtGeigel It works perfectly now! Great job sorting it out! :) – Cellydy Nov 05 '16 at 08:55
  • Hey @Cellydy, I updated this Stack Overflow post with new updates at the top. It appears many (including myself) are seeing issues again, albeit not as often as before. Just wanted to update you. – Art Geigel Nov 16 '16 at 15:10
  • Only working solution I could find after hours of trying everything! Awesome! – Garavani Feb 03 '17 at 17:21
6

I found that solution from Byron Dokimakis is worked.

However, some of you maybe get this error when try to access iframe of cross origin.

DOMException: Blocked a frame with origin from accessing a cross-origin frame.

I found a hackish way to fix this. I noticed that the cross-origin exception not showed if the google docs page is empty (204).

So we can use try catch here

Here is the example of my codes:

const PdfViewer = ({ url }) => {
  const iframeRef = useRef(null);
  const interval = useRef();

  const pdfUrl = createGdocsUrl(url);

  const [loaded, setLoaded] = useState(false);

  const clearCheckingInterval = () => {
    clearInterval(interval.current);
  };

  const onIframeLoaded = () => {
    clearCheckingInterval();
    setLoaded(true);
  };

  useEffect(() => {
    interval.current = setInterval(() => {
      try {
        // google docs page is blank (204), hence we need to reload the iframe.
        if (iframeRef.current.contentWindow.document.body.innerHTML === '') {
          iframeRef.current.src = pdfUrl;
        }
      } catch (e) {
        // google docs page is being loaded, but will throw CORS error.
        // it mean that the page won't be blank and we can remove the checking interval.
        onIframeLoaded();
      }
    }, 4000); // 4000ms is reasonable time to load 2MB document

    return clearCheckingInterval;
  }, []);

  return (
    <div className={css['pdf-iframe__wrapper']}>
      <iframe
        ref={iframeRef}
        className={css['pdf-iframe__inside']}
        frameBorder="no"
        onLoad={onIframeLoaded}
        src={pdfUrl}
        title="PDF Viewer"
      />

      {!loaded && (
        <div className={css['pdf-iframe__skeleton']}>
          <Skeleton height="100%" rectRadius={{ rx: 0, ry: 0 }} width="100%" />
        </div>
      )}
    </div>
  );
};
Luki Centuri
  • 185
  • 1
  • 6
4

Here is a react example in functional component

import React, {useEffect, useRef, useState} from "react";

type IframeGoogleDocsProps = {
    url: string,
    className?: string
};
export default function IframeGoogleDoc({url, className}: IframeGoogleDocsProps) {

    const [iframeTimeoutId, setIframeTimeoutId] = useState(undefined);
    const iframeRef = useRef(null);

    useEffect(()=>{
        const intervalId = setInterval(
            updateIframeSrc, 1000 * 3
        );
        setIframeTimeoutId(intervalId)
    },[]);

    function iframeLoaded() {
        clearInterval(iframeTimeoutId);
    }
    function getIframeLink() {
        return `https://docs.google.com/gview?url=${url}&embedded=true`;
    }
    function updateIframeSrc() {
        if(iframeRef.current){
            iframeRef.current.src = getIframeLink();
        }
    }

    return (
        <iframe
            className={className}
            onLoad={iframeLoaded}
            onError={updateIframeSrc}
            ref={iframeRef}
            src={getIframeLink()}
        />
    );
}
Ihsan Müjdeci
  • 914
  • 1
  • 9
  • 14
  • 2
    Had to make a few changes for this to work - https://gist.github.com/RusseII/62a304c29af402292ef4c57a1cf1a988 – Russell Ratcliffe May 19 '20 at 21:40
  • Be warned this gview is giving us issues at the moment. Users with slow internet will have a forever loading issue. There seems to be no way around it. – Ihsan Müjdeci May 26 '20 at 04:14
  • 2
    To get rid of the infinite loading issue you can either increase the interval time, or double the wait time every time it fails to load. Not pretty, but will ensure that it eventually works 100% of the time. – Russell Ratcliffe Jun 16 '20 at 16:27
  • @RussellRatcliffe I think some sort of back off mechanism would be the better approach definitely. – Ihsan Müjdeci Aug 02 '21 at 01:00
2

A simple solution/hack with Reactjs, though can be easily implemented to any other library/vanilla.

Used with a basic concept : tries to load - if onload accomplish, clear interval, otherwise try to load again every 3 sec. works perfectly

(I've edited my own code it so it will contain minimum code, so not tested)

var React = require('react');

export default class IframeGoogleDocs extends React.Component {
    constructor(props) {
        super();
        this.bindActions();
    }
    bindActions() {
        this.updateIframeSrc = this.updateIframeSrc.bind(this);
        this.iframeLoaded = this.iframeLoaded.bind(this);
    }
    iframeLoaded() {
        clearInterval(this.iframeTimeoutId);
    }
    getIframeLink() {
        return `https://docs.google.com/gview?url=${this.props.url}`; // no need for this if thats not dynamic
    }
    updateIframeSrc() {
        this.refs.iframe.src = this.getIframeLink();
    }
    componentDidMount() {
        this.iframeTimeoutId = setInterval(
            this.updateIframeSrc, 1000 * 3
        );
    }
    render() {
        return (
            <iframe onLoad={this.iframeLoaded} onError={this.updateIframeSrc} ref="iframe" src={this.getIframeLink()}></iframe>
        );
    }
}
jony89
  • 5,155
  • 3
  • 30
  • 40
2

I got maybe a dumb question but, why we check if document is loaded? Isn't way easy to catch the response 204 and refresh until we get 200 (then we are sure that document is loaded) :)

xkp
  • 33
  • 6
1

I was using the Google Viewer as a copy viewer for our internal management system, we generally only upload PDF's and image files, so as a all-in-one solution is was brilliant, worked across the board (mobile, desktop etc). However with it becoming increasingly unreliable, I got creative.

My solution was to generate and save a JPG version of the PDF using imagick if it was viewed after being uploaded. Rather than batching all of the uploaded PDFs, they are only converted when they are accessed.

My reasoning for that is:

  1. I have a very small user pool so file types are easily managed
  2. The likelihood of every PDF needing to be viewed again after upload is almost nil, so it's only created when needed for reporting purposes.
  3. I need a reliable way of viewing the file via mobile devices. iOS and Android do not play well with in browser PDF viewers and everyone knows how much hassle PDF's are on an iOS device (iBooks anyone?)

Once the file has been viewed and a jpg version of the pdf created, it is used in place of the PDF whenever it is viewed by a user. Not pretty but certainly works, I admit there is an element of doubling up however I do not have any storage limitations. The original file is also not modified in anyway so it serves as a tertiary remote backup too. This is not by design, but a happy coincidence.

Feel free to use the code below if it's useful to you. There are probably more elegant ways to do this, but for my purposes and users it's fine.

            $_thumbnail = 'files/thumbnails/'.$_section.'/'.$_fileName.'.jpg';

            if (!file_exists($_thumbnail)) {

                    $_file = 'files/'.$_section.'/'.$_fileName;

                    $imagePreview = new imagick();
                    $imagePreview->setResolution(300, 300);
                    $imagePreview->readimage($_file);
                    $imagePreview->setImageFormat( "jpg" );
                    $imagePreview->writeImage('files/thumbnails/'.$_section.'/'.$_fileName.'.jpg');

                    echo '<img src="/files/thumbnails/'.$_section.'/'.$_fileName.'.jpg" width="100%"/>';

            } else {
                    echo '<img src="/files/thumbnails/'.$_section.'/'.$_fileName.'.jpg" width="100%"/>';

            }
B Wake
  • 11
  • 3
1

I solved this problem as follows. If google viewer is not loaded, make iframe restart.

function reloadIFrame() {
var iframe = document.getElementById("iFrame");
  console.log(frame.contentDocument.URL); //work control
  if(iframe.contentDocument.URL == "about:blank"){
    iframe.src =  iframe.src;
  }
}
var timerId = setInterval("reloadIFrame();", 2000);

$( document ).ready(function() {
    $('#menuiFrame').on('load', function() {
        clearInterval(timerId);
        console.log("Finally Loaded"); //work control
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<iframe id="iFrame" src="https://docs.google.com/gview?url=http:exemple.pdf?entryPoint=projectimage&id=1bef4781-5eb5-60b0-8f0b-5426c9877ebe&type=apoll_Web_Project_Files&embedded=true" style="width:718px; height:700px;" frameborder="0"></iframe>
0

I was able to get this to work with Тетяна Волошка's answer, however I had to remove the if statement because

This

iframe.contentDocument.URL == "about:blank"

caused

DOMException: Blocked a frame with origin from accessing a cross-origin frame.

I'm not quite sure why this fixed it for me. Perhaps the 2 second delay allowed everything else on my page to load and remove any conflict for the embedded pdf to load, but how else could i get the content document without a the cross-origin issue?

dev-jeff
  • 173
  • 9
0

Thought I'd share this solution here also, as the answers above won't work efficiently for a large document: The load event will not fire for a few seconds after the iFrame has started loading, so you might end up with an endless loop. A better solution is to also check for the size of the body of the iFrame.

  • Add the answer to your own post; Do not merely link to it. – HappyFace Oct 19 '20 at 03:15
  • Hey @HappyFace. I can't seem to find a specific guideline against sharing an answer via a link (with the appropriate context, of course). I would think this is preferable, to avoid duplicate content and have only 1 point of reference for any potential future amendments to the answer. If you have another view, let me know. – Byron Dokimakis Oct 25 '20 at 14:03
  • https://meta.stackoverflow.com/questions/251006/flagging-link-only-answers – HappyFace Oct 25 '20 at 14:14
0

After spending lot of time I finally found solution!!!

Best Option is to use Free service provided by Adobe, PDF embed API.

HERE

  1. Create your Project
  2. Get your Client ID
  3. Add your domain(it will only work for that domain)
Aimanzaki
  • 566
  • 6
  • 9