2

I need to send back a bit of data for reporting when the user closes or leaves a specific page. So I set up an API endpoint and am using window.fetch with the keepalive flag set to make sure that the call completes even if the page unloads completely.

The Javascript call in question looks like this:

async onLeavingPage() {
    (preparing data for call)
    const response = await fetch(
        (url),
        {
            keepalive: true,
            method: "POST",
            mode: "cors",
            headers: {
                "Content-Type": "application/json",
                Authorization: axios.defaults.headers.common["Authorization"]
            },
            body: JSON.stringify({})
        }
    );
    console.log(response);
}

I'm calling it by watching for the pagevisibility event and calling it when the page is hidden or terminated, using the page-lifecycle library.

lifecycle.addEventListener("statechange", (e) => {
            if (e.newState === "hidden" || e.newState === "terminated") {
                this.onLeavingPage();
            }
        });

The preferred behavior is for the call to be completed, even if the page is reloaded or another link is clicked on. But thanks to this CORS error, it's not happening. It works fine in Chrome and Firefox, but in Safari it fails with this error message in the console:

Fetch API cannot load (api endpoint) due to access control checks.

The same fetch call works in Safari if it's called in any other circumstance (like, say, clicking a link or minimizing and then maximizing the page), so it's something specific to calling it on page unload.

6
  • You may be hitting a known bug in Safari, related to visibilitychange not firing as expected during page navigations; see bugs.webkit.org/show_bug.cgi?id=151234. Maybe try testing in Safari Technology Preview, and see if it works as expected there.
    – sideshowbarker
    Commented Jan 14, 2021 at 2:39
  • stackoverflow.com/q/57393717/441757 and stackoverflow.com/q/48101355/441757 may be caused by the same underlying problem.
    – sideshowbarker
    Commented Jan 14, 2021 at 2:52
  • I think the workaround you might want to try is to listen for the pagehide event, which does reliably fire in Safari even when visibilitychange doesn’t.
    – sideshowbarker
    Commented Jan 14, 2021 at 2:57
  • 1
    I had it console.log when visibility changes. As far as I can see, it's firing as expected, even in Safari. I'm using npmjs.com/package/page-lifecycle to detect lifecycle events, and it has code to handle Safari not firing visibilitychange consistently. Although I wonder if the fact that Safari is using beforeunload as a replacement might have something to do with it. Commented Jan 14, 2021 at 5:32
  • OK, yeah I guessed that library must be written to be smart enough to abstract away the Safari problem. But anyway, I still wonder if the CORS error is in fact a side effect of some other problem — not the other way around. I guess one way to isolate that would be to retry it all in a test environment where the frontend code and the API endpoint are same-origin rather than cross-origin. If it didn’t work even when the request is same-origin, then you’d know the root cause wasn’t a CORS issue — and of course on th other hand, if it did work, you’d know that cause really has to be a CORS issue.
    – sideshowbarker
    Commented Jan 14, 2021 at 6:03

0