Search code examples
javascriptnode.jsfacebook-graph-apigoogle-apps-scripturlfetch

Why does Google Apps Script's UrlFetchApp return HTML instead of csv file (requesting Facebook API)?


Background

UrlFetchApp responds with an html file instead of a csv file when I'm requesting a report via the facebook insights API. From the Facebook documentation- bottom of the page:

Export Reports

We provide a convenience endpoint for exporting to a localized human-readable format. to a localized human-readable format.

curl -G \
  -d 'report_run_id=<AD_REPORT_RUN_ID>' \
  -d 'name=myreport' \
  -d 'format=csv' \
'https://www.facebook.com/ads/ads_insights/export_report/'

I have already ran the report and therefore have got an adReportId and authentication is no issue as I'm using a valid access_token. In fact, when I visit the url manually the download of the correct csv file starts immediately.

The Problem

When parsing the csv response Google Apps Script throws the following error:

Could not parse text. (line 219, file)

Lines 215-219:

function getReportData(reportId) {
  const id = reportId || CacheService.getScriptCache().get('campaign-report-id');
  const facebookUrl = buildFacebookReportUrl(id);
  //facebookUrl:https://www.facebook.com/ads/ads_insights/export_report?report_run_id=<REPORT_ID>&format=csv&access_token=<ACCESS_TOKEN>
  var fetchRequest = UrlFetchApp.fetch(facebookUrl);
  var response = fetchRequest.getContentText();
  Logger.log(response);
  return Utilities.parseCsv(fetchRequest)
    };

function buildFacebookReportUrl(reportId) {
  const baseUrl = `https://www.facebook.com/ads/ads_insights/export_report?`;
  const paramString = `report_run_id=${reportId}&format=csv&access_token=${
    fbConfig.TOKEN}`;
  const requestUrl = `${baseUrl}${paramString}`;
  return encodeURI(requestUrl);
}

The log shows the following data for response (truncated):

<!DOCTYPE html>
<html lang="en" id="facebook" class="no_js">

<head>
    <meta charset="utf-8" />
    <meta name="referrer" content="default" id="meta_referrer" />
    <script>
        window._cstart = +new Date();
    </script>
    <script>
        function envFlush(a) {
            function b(b) {
                for (var c in a) b[c] = a[c]
            }
            window.requireLazy ? window.requireLazy(["Env"], b) : (window.Env = window.Env || {}, b(window.Env))
        }
        envFlush({
            "ajaxpipe_token": "AXjyFTuniyv5Ka6j",
            "timeslice_heartbeat_config": {
                "pollIntervalMs": 33,
                "idleGapThresholdMs": 60,
                "ignoredTimesliceNames": {
                    "requestAnimationFrame": true,
                    "Event listenHandler mousemove": true,
                    "Event listenHandler mouseover": true,
                    "Event listenHandler mouseout": true,
                    "Event listenHandler scroll": true
                },
                "isHeartbeatEnabled": true,
                "isArtilleryOn": false
            },
            "shouldLogCounters": true,
            "timeslice_categories": {
                "react_render": true,
                "reflow": true
            },
            "sample_continuation_stacktraces": true,
            "dom_mutation_flag": true,
            "stack_trace_limit": 30,
            "deferred_stack_trace_rate": 1000,
            "timesliceBufferSize": 5000,
            "show_invariant_decoder": false,
            "compat_iframe_token": "AQ7vXO7c6UeVAX4i",
            "isCQuick": false
        });
    </script>
    <style></style>
    <script>
        __DEV__ = 0;
        CavalryLogger = window.CavalryLogger || function(a) {
            this.lid = a, this.transition = !1, this.metric_collected = !1, this.is_detailed_profiler = !1, this.instrumentation_started = !1, this.pagelet_metrics = {}, this.events = {}, this.ongoing_watch = {}, this.values = {
                t_cstart: window._cstart
            }, this.piggy_values = {}, this.bootloader_metrics = {}, this.resource_to_pagelet_mapping = {}, this.initializeInstrumentation && this.initializeInstrumentation()
        }, CavalryLogger.prototype.setIsDetailedProfiler = function(a) {
            this.is_detailed_profiler = a;
            return this
        }, CavalryLogger.prototype.setTTIEvent = function(a) {
            this.tti_event = a;
            return this
        }, CavalryLogger.prototype.setValue = function(a, b, c, d) {
            d = d ? this.piggy_values : this.values;
            (typeof d[a] === "undefined" || c) && (d[a] = b);
            return this
        }, CavalryLogger.prototype.getLastTtiValue = function() {
            return this.lastTtiValue
        }, CavalryLogger.prototype.setTimeStamp = CavalryLogger.prototype.setTimeStamp || function(a, b, c, d) {
            this.mark(a);
            var e = this.values.t_cstart || this.values.t_start;
            e = d ? e + d : CavalryLogger.now();
            this.setValue(a, e, b, c);
            this.tti_event && a == this.tti_event && (this.lastTtiValue = e, this.setTimeStamp("t_tti", b));
            return this
        }, CavalryLogger.prototype.mark = typeof console === "object" && console.timeStamp ? function(a) {
            console.timeStamp(a)
        } : function() {}, CavalryLogger.prototype.addPiggyback = function(a, b) {
            this.piggy_values[a] = b;
            return this
        }, CavalryLogger.instances = {}, CavalryLogger.id = 0, CavalryLogger.disableArtilleryOnUntilOffLogging = !1, CavalryLogger.getInstance = function(a) {
            typeof a === "undefined" && (a = CavalryLogger.id);
            CavalryLogger.instances[a] || (CavalryLogger.instances[a] = new CavalryLogger(a));
            return CavalryLogger.instances[a]
        }, CavalryLogger.setPageID = function(a) {
            if (CavalryLogger.id === 0) {
                var b = CavalryLogger.getInstance();
                CavalryLogger.instances[a] = b;
                CavalryLogger.instances[a].lid = a;
                delete CavalryLogger.instances[0]
            }
            CavalryLogger.id = a
        }, CavalryLogger.now = function() {
            return window.performance && performance.timing && performance.timing.navigationStart && performance.now ? performance.now() + performance.timing.navigationStart : new Date().getTime()
        }, CavalryLogger.prototype.measureResources = function() {}, CavalryLogger.prototype.profileEarlyResources = function() {}, CavalryLogger.getBootloaderMetricsFromAllLoggers = function() {}, CavalryLogger.start_js = function() {}, CavalryLogger.done_js = function() {};
        CavalryLogger.getInstance().setTTIEvent("t_domcontent");
        CavalryLogger.prototype.measureResources = function(a, b) {
            if (!this.log_resources) return;
            var c = "bootload/" + a.name;
            if (this.bootloader_metrics[c] !== void 0 || this.ongoing_watch[c] !== void 0) return;
            var d = CavalryLogger.now();
            this.ongoing_watch[c] = d;
            "start_" + c in this.bootloader_metrics || (this.bootloader_metrics["start_" + c] = d);
            b && !("tag_" + c in this.bootloader_metrics) && (this.bootloader_metrics["tag_" + c] = b);
            if (a.type === "js") {
                c = "js_exec/" + a.name;
                this.ongoing_watch[c] = d
            }
        }, CavalryLogger.prototype.stopWatch = function(a) {
            if (this.ongoing_watch[a]) {
                var b = CavalryLogger.now(),
                    c = b - this.ongoing_watch[a];
                this.bootloader_metrics[a] = c;
                var d = this.piggy_values;
                a.indexOf("bootload") === 0 && (d.t_resource_download || (d.t_resource_download = 0), d.resources_downloaded || (d.resources_downloaded = 0), d.t_resource_download += c, d.resources_downloaded += 1, d["tag_" + a] == "_EF_" && (d.t_pagelet_cssload_early_resources = b));
                delete this.ongoing_watch[a]
            }
            return this
        }, CavalryLogger.getBootloaderMetricsFromAllLoggers = function() {
            var a = {};
            Object.values(window.CavalryLogger.instances).forEach(function(b) {
                b.bootloader_metrics && Object.assign(a, b.bootloader_metrics)
            });
            return a
        }, CavalryLogger.start_js = function(a) {
            for (var b = 0; b < a.length; ++b) CavalryLogger.getInstance().stopWatch("js_exec/" + a[b])
        }, CavalryLogger.done_js = function(a) {
            for (var b = 0; b < a.length; ++b) CavalryLogger.getInstance().stopWatch("bootload/" + a[b])
        }, CavalryLogger.prototype.profileEarlyResources = function(a) {
            for (var b = 0; b < a.length; b++) this.measureResources({
                name: a[b][0],
                type: a[b][1] ? "js" : ""
            }, "_EF_")
        };
        CavalryLogger.getInstance().log_resources = true;
        CavalryLogger.getInstance().setIsDetailedProfiler(true);
        window.CavalryLogger && CavalryLogger.getInstance().setTimeStamp("t_start");
    </script>
    <title id="pageTitle">Facebook</title>
    <link rel="shortcut icon" href="https://static.xx.fbcdn.net/rsrc.php/yz/r/KFyVIAWzntM.ico" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y2/l/0,cross/3kNz1uzYvN2.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="SUv1J" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yW/l/0,cross/9NGO1GuacRK.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="nOHzA" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yA/l/0,cross/rvNB4fphdT0.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="T1Fcr" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yJ/l/0,cross/kDxV0y2UotM.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="cNDmN" />
    <script src="https://static.xx.fbcdn.net/rsrc.php/v3/yh/r/53ZB62AZOTo.js?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="QPWJc"></script>
    <script>
        requireLazy(["gkx"], function(gkx) {
            gkx.add({
                "676837": {
                    "result": false,
                    "hash": "AT5qgm2lluu0ObEm"
                },
                "676920": {
                    "result": false,
                    "hash": "AT4fRx_5a-x5BCKq"
                },
                "676921": {
                    "result": false,
                    "hash": "AT7L2NIsWs1k6mzF"
                },
                "676922": {
                    "result": false,
                    "hash": "AT434PRa2zIf0VNU"
                },
                "676940": {
                    "result": false,
                    "hash": "AT75c1NCKpiznkoK"
                },
                "946894": {
                    "result": false,
                    "hash": "AT4KxZoaFuONM6jW"
                },
                "996939": {
                    "result": false,
                    "hash": "AT7CXDiWhrCd8u4n"
                },
                "996940": {
                    "result": false,
                    "hash": "AT4S6r3cOh4ebic8"
                },
                "1073500": {
                    "result": false,
                    "hash": "AT6ny6L_AsBsjSUH"
                },
                "1113247": {
                    "result": false,
                    "hash": "AT6aSDBxHRQgvz2h"
                },
                "1263340": {
                    "result": false,
                    "hash": "AT4j6MH_K-2kudmO"
                },
                "1167394": {
                    "result": false,
                    "hash": "AT7tg1d7ZhRzO_3p"
                }
            });
        });
        requireLazy(["qex"], function(qex) {
            qex.add({
                "1211266": {
                    "r": null
                }
            });
        });
        require("TimeSliceImpl").guard(function() {
                    (require("ServerJSDefine")).handleDefines([
                                ["cr:696703", [], {
                                    "__rc": [null, "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:708886", ["EventProfilerImpl"], {
                                    "__rc": ["EventProfilerImpl", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:717822", ["TimeSliceImpl"], {
                                    "__rc": ["TimeSliceImpl", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:806696", ["clearTimeoutBlue"], {
                                    "__rc": ["clearTimeoutBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:807042", ["setTimeoutBlue"], {
                                    "__rc": ["setTimeoutBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:896462", ["setIntervalAcrossTransitionsBlue"], {
                                    "__rc": ["setIntervalAcrossTransitionsBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:986633", ["setTimeoutAcrossTransitionsBlue"], {
                                    "__rc": ["setTimeoutAcrossTransitionsBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:1003267", ["clearIntervalBlue"], {
                                    "__rc": ["clearIntervalBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:1100101", ["requestAni [20 - 01 - 28 15: 24: 04: 186 CET] < !DOCTYPE html >
                                        < html lang = "en"
                                        id = "facebook"
                                        class = "no_js" >
                                        < head > < meta charset = "utf-8" / > < meta name = "referrer"
                                        content = "default"
                                        id = "meta_referrer" / > < script > window._cstart = +new Date();
    </script>
    <script>
        function envFlush(a) {
            function b(b) {
                for (var c in a) b[c] = a[c]
            }
            window.requireLazy ? window.requireLazy(["Env"], b) : (window.Env = window.Env || {}, b(window.Env))
        }
        envFlush({
            "ajaxpipe_token": "AXjyFTuniyv5Ka6j",
            "timeslice_heartbeat_config": {
                "pollIntervalMs": 33,
                "idleGapThresholdMs": 60,
                "ignoredTimesliceNames": {
                    "requestAnimationFrame": true,
                    "Event listenHandler mousemove": true,
                    "Event listenHandler mouseover": true,
                    "Event listenHandler mouseout": true,
                    "Event listenHandler scroll": true
                },
                "isHeartbeatEnabled": true,
                "isArtilleryOn": false
            },
            "shouldLogCounters": true,
            "timeslice_categories": {
                "react_render": true,
                "reflow": true
            },
            "sample_continuation_stacktraces": true,
            "dom_mutation_flag": true,
            "stack_trace_limit": 30,
            "deferred_stack_trace_rate": 1000,
            "timesliceBufferSize": 5000,
            "show_invariant_decoder": false,
            "compat_iframe_token": "AQ7vXO7c6UeVAX4i",
            "isCQuick": false
        });
    </script>
    <style></style>
    <script>
        __DEV__ = 0;
        CavalryLogger = window.CavalryLogger || function(a) {
            this.lid = a, this.transition = !1, this.metric_collected = !1, this.is_detailed_profiler = !1, this.instrumentation_started = !1, this.pagelet_metrics = {}, this.events = {}, this.ongoing_watch = {}, this.values = {
                t_cstart: window._cstart
            }, this.piggy_values = {}, this.bootloader_metrics = {}, this.resource_to_pagelet_mapping = {}, this.initializeInstrumentation && this.initializeInstrumentation()
        }, CavalryLogger.prototype.setIsDetailedProfiler = function(a) {
            this.is_detailed_profiler = a;
            return this
        }, CavalryLogger.prototype.setTTIEvent = function(a) {
            this.tti_event = a;
            return this
        }, CavalryLogger.prototype.setValue = function(a, b, c, d) {
            d = d ? this.piggy_values : this.values;
            (typeof d[a] === "undefined" || c) && (d[a] = b);
            return this
        }, CavalryLogger.prototype.getLastTtiValue = function() {
            return this.lastTtiValue
        }, CavalryLogger.prototype.setTimeStamp = CavalryLogger.prototype.setTimeStamp || function(a, b, c, d) {
            this.mark(a);
            var e = this.values.t_cstart || this.values.t_start;
            e = d ? e + d : CavalryLogger.now();
            this.setValue(a, e, b, c);
            this.tti_event && a == this.tti_event && (this.lastTtiValue = e, this.setTimeStamp("t_tti", b));
            return this
        }, CavalryLogger.prototype.mark = typeof console === "object" && console.timeStamp ? function(a) {
            console.timeStamp(a)
        } : function() {}, CavalryLogger.prototype.addPiggyback = function(a, b) {
            this.piggy_values[a] = b;
            return this
        }, CavalryLogger.instances = {}, CavalryLogger.id = 0, CavalryLogger.disableArtilleryOnUntilOffLogging = !1, CavalryLogger.getInstance = function(a) {
            typeof a === "undefined" && (a = CavalryLogger.id);
            CavalryLogger.instances[a] || (CavalryLogger.instances[a] = new CavalryLogger(a));
            return CavalryLogger.instances[a]
        }, CavalryLogger.setPageID = function(a) {
            if (CavalryLogger.id === 0) {
                var b = CavalryLogger.getInstance();
                CavalryLogger.instances[a] = b;
                CavalryLogger.instances[a].lid = a;
                delete CavalryLogger.instances[0]
            }
            CavalryLogger.id = a
        }, CavalryLogger.now = function() {
            return window.performance && performance.timing && performance.timing.navigationStart && performance.now ? performance.now() + performance.timing.navigationStart : new Date().getTime()
        }, CavalryLogger.prototype.measureResources = function() {}, CavalryLogger.prototype.profileEarlyResources = function() {}, CavalryLogger.getBootloaderMetricsFromAllLoggers = function() {}, CavalryLogger.start_js = function() {}, CavalryLogger.done_js = function() {};
        CavalryLogger.getInstance().setTTIEvent("t_domcontent");
        CavalryLogger.prototype.measureResources = function(a, b) {
            if (!this.log_resources) return;
            var c = "bootload/" + a.name;
            if (this.bootloader_metrics[c] !== void 0 || this.ongoing_watch[c] !== void 0) return;
            var d = CavalryLogger.now();
            this.ongoing_watch[c] = d;
            "start_" + c in this.bootloader_metrics || (this.bootloader_metrics["start_" + c] = d);
            b && !("tag_" + c in this.bootloader_metrics) && (this.bootloader_metrics["tag_" + c] = b);
            if (a.type === "js") {
                c = "js_exec/" + a.name;
                this.ongoing_watch[c] = d
            }
        }, CavalryLogger.prototype.stopWatch = function(a) {
            if (this.ongoing_watch[a]) {
                var b = CavalryLogger.now(),
                    c = b - this.ongoing_watch[a];
                this.bootloader_metrics[a] = c;
                var d = this.piggy_values;
                a.indexOf("bootload") === 0 && (d.t_resource_download || (d.t_resource_download = 0), d.resources_downloaded || (d.resources_downloaded = 0), d.t_resource_download += c, d.resources_downloaded += 1, d["tag_" + a] == "_EF_" && (d.t_pagelet_cssload_early_resources = b));
                delete this.ongoing_watch[a]
            }
            return this
        }, CavalryLogger.getBootloaderMetricsFromAllLoggers = function() {
            var a = {};
            Object.values(window.CavalryLogger.instances).forEach(function(b) {
                b.bootloader_metrics && Object.assign(a, b.bootloader_metrics)
            });
            return a
        }, CavalryLogger.start_js = function(a) {
            for (var b = 0; b < a.length; ++b) CavalryLogger.getInstance().stopWatch("js_exec/" + a[b])
        }, CavalryLogger.done_js = function(a) {
            for (var b = 0; b < a.length; ++b) CavalryLogger.getInstance().stopWatch("bootload/" + a[b])
        }, CavalryLogger.prototype.profileEarlyResources = function(a) {
            for (var b = 0; b < a.length; b++) this.measureResources({
                name: a[b][0],
                type: a[b][1] ? "js" : ""
            }, "_EF_")
        };
        CavalryLogger.getInstance().log_resources = true;
        CavalryLogger.getInstance().setIsDetailedProfiler(true);
        window.CavalryLogger && CavalryLogger.getInstance().setTimeStamp("t_start");
    </script>
    <title id="pageTitle">Facebook</title>
    <link rel="shortcut icon" href="https://static.xx.fbcdn.net/rsrc.php/yz/r/KFyVIAWzntM.ico" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y2/l/0,cross/3kNz1uzYvN2.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="SUv1J" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yW/l/0,cross/9NGO1GuacRK.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="nOHzA" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yA/l/0,cross/rvNB4fphdT0.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="T1Fcr" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yJ/l/0,cross/kDxV0y2UotM.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="cNDmN" />
    <script src="https://static.xx.fbcdn.net/rsrc.php/v3/yh/r/53ZB62AZOTo.js?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="QPWJc"></script>
    <script>
        requireLazy(["gkx"], function(gkx) {
            gkx.add({
                "676837": {
                    "result": false,
                    "hash": "AT5qgm2lluu0ObEm"
                },
                "676920": {
                    "result": false,
                    "hash": "AT4fRx_5a-x5BCKq"
                },
                "676921": {
                    "result": false,
                    "hash": "AT7L2NIsWs1k6mzF"
                },
                "676922": {
                    "result": false,
                    "hash": "AT434PRa2zIf0VNU"
                },
                "676940": {
                    "result": false,
                    "hash": "AT75c1NCKpiznkoK"
                },
                "946894": {
                    "result": false,
                    "hash": "AT4KxZoaFuONM6jW"
                },
                "996939": {
                    "result": false,
                    "hash": "AT7CXDiWhrCd8u4n"
                },
                "996940": {
                    "result": false,
                    "hash": "AT4S6r3cOh4ebic8"
                },
                "1073500": {
                    "result": false,
                    "hash": "AT6ny6L_AsBsjSUH"
                },
                "1113247": {
                    "result": false,
                    "hash": "AT6aSDBxHRQgvz2h"
                },
                "1263340": {
                    "result": false,
                    "hash": "AT4j6MH_K-2kudmO"
                },
                "1167394": {
                    "result": false,
                    "hash": "AT7tg1d7ZhRzO_3p"
                }
            });
        });
        requireLazy(["qex"], function(qex) {
            qex.add({
                "1211266": {
                    "r": null
                }
            });
        });
        require("TimeSliceImpl").guard(function() {
                    (require("ServerJSDefine")).handleDefines([
                                ["cr:696703", [], {
                                    "__rc": [null, "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:708886", ["EventProfilerImpl"], {
                                    "__rc": ["EventProfilerImpl", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:717822", ["TimeSliceImpl"], {
                                    "__rc": ["TimeSliceImpl", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:806696", ["clearTimeoutBlue"], {
                                    "__rc": ["clearTimeoutBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:807042", ["setTimeoutBlue"], {
                                    "__rc": ["setTimeoutBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:896462", ["setIntervalAcrossTransitionsBlue"], {
                                    "__rc": ["setIntervalAcrossTransitionsBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:986633", ["setTimeoutAcrossTransitionsBlue"], {
                                    "__rc": ["setTimeoutAcrossTransitionsBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:1003267", ["clearIntervalBlue"], {
                                    "__rc": ["clearIntervalBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:1100101", ["requestAni

What I've tried (other stackoverflow solutions)

  • This question claims that a similar urlFetch request yielded the csv content, however I don't understand the additional options he puts in (I don't think I need it as authentication is no issue and it works when manually visiting the url)
  • This questions has the same issue but the only response is towards authentication issues which I can exclude in my case.
  • I have tried this implementation (getting the blob) as well resulting in a Google Apps Script error when trying to unzip the blob.
  • This question made me check the csv file for any possible malformation, however after inspection and manual importing into google sheets everything looked fine: enter image description here
  • Thanks to @TheMaster who pointed out encoding I've also added above the buildFacebookReportUrl() function and have also tried encodeURIComponent() for the token and reportId -- without success though:
function buildFacebookReportUrl(reportId) {
  const baseUrl = `https://www.facebook.com/ads/ads_insights/export_report?`;
  const paramString = `report_run_id=${encodeURIComponent(reportId)}&format=csv&access_token=${encodeURIComponent(
    fbConfig.TOKEN
  )}`;
  const requestUrl = `${baseUrl}${paramString}`;
  return encodeURI(requestUrl);
}

How to reproduce

  1. Facebook Insights API Quickstart
  2. Send a POST request to /insights endpoint, which responds with the id of an Ad Report Run.
  3. Export Report like in the Example above

I hope someone can reproduce this error or spots immediately what's wrong with my request.

Let me know if you need more context! (Don't have a lot of experience but tried my best giving context)


Solution

  • Posting an answer as I finally found out what was wrong.

    The problem is that I made an asynchronous request to create the report and wanted to download it before the job was completed.

    From Facebook documentation:

    1. Send a POST request to <AD_OBJECT>/insights endpoint, which responds with the id of an Ad Report Run.
    2. Ad Report Runs contain information about this asynchronous job, such as async_status. Poll this field until async_status is Job Completed and async_percent_completion is 100.
    3. Then you can query <AD_REPORT_RUN_ID>/insights edge to fetch the final result.

    I tried to do 3. before conditions in step 2 were fulfilled.

    The Solution

    I have added a while loop polling the async_status field as recommended.

    function fetchReportAndSaveToSheet() {
      const reportId = createReportAndReturnId();
      //THE FOLLOWING CODE HAS SOLVED MY ISSUE
      let jobIsCompleted = false;
      const runReportAdsUrl = `https://graph.facebook.com/v5.0/${reportId}?access_token=${fbConfig.TOKEN}`;
      while (!jobIsCompleted) {
        const fetchRequest = UrlFetchApp.fetch(runReportAdsUrl));
        const runReportAds = JSON.parse(fetchRequest.getContentText());
        jobIsCompleted= runReportAds.async_status === 'Job Completed';
        if (runReportAds.async_status === 'Job Failed') {
          Logger.log((runReportAds.async_status))
          break
        }
      //END OF CODE MODIFICATION
      }
      cacheId(reportId);
      const data = getReportData(reportId);
      clearData();
      pushReportToSheet(data);
    }
    }